nuijs
Version:
nui框架
812 lines (785 loc) • 30.5 kB
JavaScript
/**
* @author Aniu[2016-11-10 22:39]
* @update Aniu[2016-11-10 22:39]
* @version 1.0.1
* @description layer弹出层
*/
Nui.define(function(require){
this.imports('../../assets/components/layer/index');
var component = require('../../core/component');
var util = require('../../core/util');
var template = require('../../core/template');
var statics = {
_maskzIndex:10000,
_zIndex:10000,
_init:function(){
var _class = this;
var timer = null;
Nui.win.on('resize', function(){
clearTimeout(timer);
timer = setTimeout(function(){
Nui.each(_class.__instances, function(val){
var opts = val._options;
if(opts.position || opts.isCenter === true){
val.resize()
}
})
})
})
},
_$fn:null,
_$ready:null,
init:null
}
var options = {
//内容
content:'',
//内容模版
template:'',
//模版数据
data:{},
//高度
width:320,
//宽度
height:'auto',
//弹出层层级
zIndex:null,
//最大宽度
maxWidth:0,
//最大高度
maxHeight:0,
//定时器,N毫秒后自动关闭
timer:0,
//弹窗四周距离窗口边缘距离
edge:0,
//弹窗容器
container:'body',
//弹窗标题
title:'温馨提示',
//当弹窗容器不是body时,是否以window窗口计算位置
isWindow:false,
//是否可以拖动
isMove:false,
//是否有遮罩
isMask:true,
//是否只能在窗口内拖动
isInnerMove:false,
//点击遮罩是否关闭弹窗
isClickMask:false,
//是否使用遮罩拖动
isMoveMask:false,
//是否能用hide方法关闭遮罩
isHide:true,
//弹窗是否浏览器改变大小时显示在窗口中央
isCenter:true,
//是否全屏显示
isFull:false,
//是否在点击弹窗时将其置顶
isTop:false,
//是否以提示框展示,没有标题,按钮
isTips:false,
//是否拖动滚动条固定位置
isFixed:true,
//当内容超过弹出层容器,是否显示滚动条
scrollbar:true,
//是否点击弹窗或者点击遮罩层是否阻止事件冒泡
isStopProp:false,
//按钮对齐方式
align:'center',
//自定义拖动元素
moveElement:null,
//是否以气泡形式展示,弹出层边缘会多出箭头
bubble:{
enable:false,
dir:'top'
},
//弹出层内容展示iframe,不建议跨域使用
iframe:{
enable:false,
cache:false,
src:''
},
//关闭按钮
close:{
enable:true,
text:'×'
},
//确定按钮
confirm:{
enable:false,
name:'normal',
text:'确定',
callback:function(){
return true
}
},
//取消按钮
cancel:{
enable:true,
text:'取消'
},
/*弹出层定位 top/left/right/bottom
position:{
top:10,
left:10
}
*/
position:null,
/*将弹出层置于遮罩层底部
under:[layer1, layer2]
*/
under:null,
/*配置按钮,若id为confirm/cancel/close将会覆盖内置按钮参数
button:[{
id:'confirm',
text:'确定',
name:'normal',
callback:function(){
}
}]
*/
button:null,
//onInit:弹出层显示时回调
//onDestroy:弹出层注销时回调
//当拖动弹出层移动后回调
onMove:null,
//窗口改变大小位置时回调
onResize:null,
//容器滚动时回调
onScroll:null,
//弹窗隐藏前回调,若返回false则不能隐藏
onHideBefore:null,
//弹窗销毁前回调,若返回false则不能销毁
onDestroyBefore:null,
//定时关闭弹窗回调
onTimer: null,
//弹窗渲染出来后回调,先于onInit
onRender: null,
}
return this.extend(component, {
_static:statics,
_options:options,
_template:{
layout:
'<div class="<% className %>" style="<% include \'style\' %>">'+
'<div class="layer-box">'+
'<%if close%>'+
'<% var btn = close %>'+
'<% include "button" %>'+
'<%/if%>'+
'<%if bubble%>'+
'<span class="layer-bubble layer-bubble-<%bubble.dir||"top"%>"'+
'<%if bubble.style%>'+
' style="<%each bubble.style v n%><%n%>:<%v%>;<%/each%>"'+
'<%/if%>'+
'><b></b><i></i></span>'+
'<%/if%>'+
'<%if title%>'+
'<div class="layer-head">'+
'<span class="layer-title"><%title%></span>'+
'</div>'+
'<%/if%>'+
'<div class="layer-body">'+
'<div class="layer-main">'+
'<%content%>'+
'</div>'+
'</div>'+
'<%if button && button.length%>'+
'<div class="layer-foot" style="text-align:<%align%>">'+
'<div class="layer-inner">'+
'<%each button btn%>'+
'<%include "button"%>'+
'<%/each%>'+
'</div>'+
'</div>'+
'<%/if%>'+
'</div>'+
'</div>',
button:
'<button type="button" class="ui-button'+
'<%if btn.name%>'+
'<%each [].concat(btn.name) name%> ui-button-<%name%><%/each%>'+
'<%/if%> layer-button-<%btn.id%>"'+
'<%if btn.style%>'+
' style="<%each btn.style v n%><%n%>:<%v%>;<%/each%>"'+
'<%/if%>><%btn.text || "按钮"%></button>',
iframe:
'<iframe<%each attr%> <%$index%>="<%$value%>"<%/each%>></iframe>',
mask:
'<div class="nui-layer-mask'+
'<%if skin%> nui-layer-mask-<%skin%><%/if%>" style="<%include \'style\'%>">'+
'<div class="layer-mask"></div>'+
'</div>',
movemask:
'<div class="nui-layer-movemask'+
'<%if skin%> nui-layer-movemask-<%skin%><%/if%>" style="<%include \'style\'%>">'+
'</div>',
style:
'<%each style%><%$index%>:<%$value%>;<%/each%>'
},
/*
top:弹窗距离窗口顶部距离
left:弹窗距离窗口左边距离
width:弹窗宽度
height:弹窗高度
*/
data:{},
_init:function(){
this._zIndex = ++this.constructor._zIndex;
this._exec()
this._emitListener('init')
},
_exec:function(){
var self = this, opts = self._options;
self._container = self._jquery(opts.container);
if(self._container){
self._containerDOM = self._container.get(0);
if(self._containerDOM.tagName !== 'BODY' && opts.isWindow !== true){
self._window = self._container;
self._isWindow = false;
var pos = self._container.css('position');
if('absolute relative fixed'.indexOf(pos) === -1){
self._container.css('position', 'relative')
}
}
else{
self._window = Nui.win;
self._isWindow = true;
}
self._isFixed = opts.isFixed === true && !Nui.bsie6 && self._isWindow;
self._create();
}
},
_create:function(){
var self = this, opts = self._options;
var buttons = self._createButton(), isTitle = false;
if(opts.isTips !== true){
isTitle = typeof opts.title === 'string';
}
var data = self._tplData({
content:self._getContent(),
close:buttons.close,
button:buttons.button,
title:isTitle ? (opts.title||'温馨提示') : null,
bubble:opts.bubble.enable === true ? opts.bubble : null,
align:opts.align || 'center',
style:{
'z-index':isNaN(parseInt(opts.zIndex)) ? self._zIndex : opts.zIndex,
'position':'absolute',
'display':'block'
}
});
if(self._isFixed){
data.style.position = 'fixed';
}
self._setTop();
opts.element = self.element = self._bindComponentName($(self._tpl2html('layout', data)).appendTo(self._container));
self._box = self.element.children('.layer-box');
self.head = self._box.children('.layer-head');
self._body = self._box.children('.layer-body');
self.main = self._body.children('.layer-main');
self.foot = self._box.children('.layer-foot');
self.moveElement = self._jquery(opts.moveElement);
if(opts.isTips !== true){
if(opts.iframe.enable === true){
self._iframe = self.main.children('iframe');
self._iframeOnload()
}
if(opts.isMove === true && (self.moveElement || isTitle)){
self._bindMove();
}
if(opts.isStopProp === true){
self._stopProp();
}
if(opts.isTop === true){
self._bindTop();
}
}
if(self._button.length){
self._buttonEvent();
}
if(opts.isFixed === true && !self._isFixed === true){
self._bindScroll()
}
self._callback('Render');
self._event();
self._show()
},
_getContent:function(){
var self = this, opts = self._options, content = '', tpl = opts.template;
if(opts.isTips !== true && opts.iframe.enable === true){
content = self._createIframe();
}
else{
if(tpl){
var data = opts.data;
if(typeof data === 'function'){
data = opts.data.call(this)
}
if(typeof tpl === 'string'){
content = template.render(tpl, data)
}
else if(Nui.type(opts.template, 'Object')){
content = template.render.call(tpl, tpl.main, data)
}
}
else if(typeof opts.content === 'string'){
content = opts.content
}
else if(opts.content instanceof jQuery){
content = opts.content.prop('outerHTML')
}
}
return content
},
_createIframe:function(){
var self = this, opts = self._options, name = 'layer-iframe'+self.__id, src = opts.iframe.src;
if(opts.iframe.cache === false){
src = util.setParam('_', new Date().getTime(), src)
}
return self._tpl2html('iframe', {
attr:{
frameborder:'0',
name:name,
id:name,
src:src,
scroll:'hidden',
style:'width:100%;'
}
})
},
_iframeOnload:function(){
var self = this;
self._iframe.load(function(){
self._iframeDocument = self._iframe.contents();
self._resize()
})
},
_createButton:function(){
var self = this, opts = self._options, defaults = {}, buttons = {}, caches = {}, isTips = opts.isTips === true;
var add = function(id, btn){
self._button[id === 'close' ? 'unshift' : 'push'](btn)
}
self._button = [];
Nui.each(['close', 'confirm', 'cancel'], function(id){
if(!isTips || id === 'close'){
var btn = opts[id];
defaults[id] = {
id:id
}
for(var i in btn){
defaults[id][i] = btn[i]
}
}
});
if(!isTips && opts.button && opts.button.length){
Nui.each(opts.button, function(val){
var id = val.id, btn = val, def;
if(!caches[id]){
caches[id] = true;
if(def = defaults[id]){
delete defaults[id]
if(!def.enable){
return true
}
btn = $.extend(true, {}, def, val);
}
add(id, btn)
}
})
}
Nui.each(defaults, function(val, id){
if(val.enable){
add(id, val)
}
});
if(self._button[0] && self._button[0].id === 'close'){
if(opts.close.enable){
buttons.close = self._button[0]
}
buttons.button = self._button.slice(1);
}
else{
buttons.button = self._button
}
return buttons
},
_buttonEvent:function(){
var self = this, opts = self._options;
Nui.each(self._button, function(val){
self._on('click', self.element, '.layer-button-'+val.id, function(e, button){
if(!button.hasClass('nui-button-disabled')){
var id = val.id, callback = val.callback;
self.triggerId = id;
var isCall = typeof callback === 'function' ? callback.call(opts, self, e, button) : null;
if((id === 'confirm' && isCall === true) || (id !== 'confirm' && isCall !== false)){
self.destroy()
}
}
})
})
},
_stopProp:function(){
this._on('click', this.element, function(e){
e.stopPropagation()
});
},
_bindTop:function(){
var self = this;
self._on('click', self.element, function(){
self._setzIndex();
});
},
_bindMove:function(){
var self = this, opts = self._options, element = self.element;
var _class = self.constructor, elem = element, isMove = false, x, y, _x, _y;
var moveElement = self.moveElement || self.head;
self._on('mousedown', moveElement, function(e, ele){
isMove = true;
self._setzIndex();
if(opts.isMoveMask === true){
elem = self._moveMask = $(self._tpl2html('movemask', {
skin:opts.skin,
style:{
'z-index':self._zIndex+1,
'cursor':'move',
'position':self._isFixed ? 'fixed' : 'absolute'
}
})).appendTo(self._container);
elem.css({
width:self.data.outerWidth - _class._getSize(elem, 'lr', 'all'),
height:self.data.outerHeight - _class._getSize(elem, 'tb', 'all'),
top:self.data.top,
left:self.data.left
});
}
ele.css('cursor','move');
x = e.pageX - self.data.left;
y = e.pageY - self.data.top;
//e.stopPropagation();
});
self._on('mousemove', Nui.doc, function(e){
var width = self._container.outerWidth(), height = self._container.outerHeight();
if(isMove){
_x = e.pageX - x;
_y = e.pageY - y;
_x < 0 && (_x = 0);
_y < 0 && (_y = 0);
if(opts.isInnerMove === true){
_x + self.data.outerWidth > width && (_x = width - self.data.outerWidth);
_y + self.data.outerHeight > height && (_y = height - self.data.outerHeight);
}
self.data.top = _y;
self.data.left = _x;
elem.css({top:_y, left:_x});
return !isMove;
}
});
self._on('mouseup', Nui.doc, function(e){
if(isMove){
isMove = false;
moveElement.css('cursor','default');
if(opts.isMoveMask === true){
element.css(self.data);
self._moveMask.remove();
self._moveMask = null;
}
self._callback('Move');
self.data.offsetTop = self.data.top - self._window.scrollTop();
self.data.offsetLeft = self.data.left - self._window.scrollLeft();
}
});
},
_bindScroll:function(){
var self = this;
self._on('scroll', self._window, function(e, elem){
var top = self.data.offsetTop + self._window.scrollTop();
var left = self.data.offsetLeft + self._window.scrollLeft();
self.data.top = top;
self.data.left = left;
self.element.css(self.data);
self._callback('Scroll', [e, elem, {top:top, left:left}]);
})
},
//鼠标点击弹出层将弹出层层级设置最大
_setzIndex:function(){
var self = this, _class = self.constructor;
if(self._isTop && self.element){
self._isTop = false;
self._zIndex = ++_class._zIndex;
self.element.css('zIndex', self._zIndex);
self._setTop();
}
},
_setLower:function(destroy){
var self = this, _class = self.constructor, opts = self._options, unders = [];
if(opts.under){
unders = unders.concat(opts.under);
if(unders.length){
Nui.each(unders, function(obj, k){
if(obj && obj.element){
obj.element.css('z-index', destroy ? (isNaN(parseInt(obj._options.zIndex)) ? obj._zIndex : obj._options.zIndex) : _class._maskzIndex-1)
}
})
}
}
},
_setTop:function(){
var self = this, _class = self.constructor;
Nui.each(_class.__instances, function(val){
if(val && val !== self && val._options.isTop === true){
val._isTop = true;
}
});
},
_position:function(){
var self = this, data = self.data, pos = self._options.position, _pos = {}, _v;
if(typeof pos === 'function'){
pos = pos.call(self._options, self)
}
Nui.each(pos, function(v, k){
if(Nui.type(v, ['String', 'Number'])){
_v = v;
if(typeof v === 'string' && v !== 'auto'){
if(!v){
_v = 0
}
else{
if(k === 'top' || k === 'bottom'){
if(v === 'self'){
_v = data.outerHeight
}
else if(/[\+\-\*\/]/.test(v)){
_v = (new Function('var self = '+data.outerHeight+'; return '+v))()
}
}
else{
if(v === 'self'){
_v = data.outerWidth
}
else if(/[\+\-\*\/]/.test(v)){
_v = (new Function('var self = '+data.outerWidth+'; return '+v))()
}
}
}
}
_pos[k] = _v
}
})
return _pos
},
_resize:function(type){
var self = this, _class = self.constructor, opts = self._options, element = self.element;
var wWidth = self._window.outerWidth();
var wHeight = self._window.outerHeight();
var stop = 0;
var sleft = 0;
if(!self._isFixed){
sleft = self._window.scrollLeft();
stop = self._window.scrollTop();
}
self._setSize();
if(opts.position){
var pos = element.css(self._position()).position();
if(Nui.bsie6){
sleft = 0;
stop = 0;
}
self.data.left = pos.left + sleft;
self.data.top = pos.top + stop;
}
else{
if(type === 'init' || opts.isCenter === true){
var left = (wWidth - self.data.outerWidth) / 2 + sleft;
var top = (wHeight - self.data.outerHeight) / 2 + stop;
var edge = opts.edge > 0 ? opts.edge : 0;
self.data.left = left > 0 ? left : edge;
self.data.top = top > 0 ? top : edge;
}
}
self.data.offsetTop = self.data.top - self._window.scrollTop();
self.data.offsetLeft = self.data.left - self._window.scrollLeft();
element.css(self.data);
},
_setSize:function(){
var self = this, _class = self.constructor, opts = self._options, element = self.element;
var edge = opts.edge > 0 ? opts.edge*2 : 0;
var wWidth = self._window.outerWidth() - edge;
var wHeight = self._window.outerHeight() - edge;
var scrollbar = opts.scrollbar;
self._body.css({height:'auto', overflow:'visible'});
element.css({top:'auto', left:'auto', width:'auto', height:'auto'});
var edgeSize = _class._getSize(self._box, 'tb', 'all') +
self.head.outerHeight() +
_class._getSize(self.head, 'tb', 'margin') +
_class._getSize(self._body, 'tb', 'all') +
self.foot.outerHeight() +
_class._getSize(self.foot, 'tb', 'margin');
var width = element.outerWidth();
if(opts.isFull !== true){
if(opts.width > 0){
width = opts.width
}
else if(opts.width === '100%' || (opts.scrollbar === true && width > wWidth)){
width = wWidth;
}
if(opts.maxWidth > 0 && width >= opts.maxWidth){
scrollbar = true;
width = opts.maxWidth
}
}
else{
width = wWidth;
}
var ws = 'nowrap';
if(opts.width > 0 || width == opts.maxWidth || width == wWidth){
ws = 'normal';
}
self.data.width = width - _class._getSize(element, 'lr', 'all');
self.main.css('white-space', ws);
element.width(self.data.width);
var height = element.outerHeight();
if(self._iframeDocument){
self._iframeDocument[0].layer = self;
height = edgeSize + self._iframeDocument.find('body').outerHeight();
}
if(opts.isFull !== true){
if(opts.height > 0){
height = opts.height
}
else if(opts.height === '100%' || ((opts.scrollbar === true || self._iframeDocument) && height > wHeight)){
height = wHeight
}
if(opts.maxHeight > 0 && height >= opts.maxHeight){
scrollbar = true;
height = opts.maxHeight
}
}
else{
height = wHeight
}
self.data.outerWidth = width;
self.data.outerHeight = height;
self.data.height = height - _class._getSize(element, 'tb', 'all');
element.height(self.data.height);
var _height = self.data.height - edgeSize;
if(self.main.outerHeight() > _height && !self._iframe && scrollbar === true){
self._body.css('overflow', 'auto')
}
if(self._iframe){
self._iframe.height(_height);
}
self._body.height(self.data.contentHeight = _height)
},
_showMask:function(){
var self = this, _class = self.constructor, opts = self._options;
if(!self._containerDOM.__layermask__){
self._containerDOM.__layermask__ = $(self._tpl2html('mask', {
skin:opts.skin,
style:{
'z-index':_class._maskzIndex,
'position':self._isFixed ? 'fixed' : 'absolute',
'top':'0px',
'left':'0px',
'width':'100%',
'height':self._isFixed ? '100%' : self._container.outerHeight()+'px'
}
})).appendTo(self._container);
}
if(opts.isStopProp === true){
self._on('click', self._containerDOM.__layermask__, function(e){
e.stopPropagation()
})
}
if(opts.isClickMask === true){
self._on('click', self._containerDOM.__layermask__, function(){
self.hide()
})
}
},
_show:function(){
var self = this, opts = self._options;
component.init(self.main);
self._resize('init');
self._setLower();
if(opts.isMask === true){
self._showMask()
}
if(opts.timer > 0){
self._time = opts.timer;
self._timer();
}
self._callback('Init');
return self
},
_timer:function(){
var self = this, opts = self._options;
if(self._time > 0){
self._callback('Timer', [self._time]);
self._timerid = setTimeout(function(){
self._time -= 1000;
self._timer();
}, self._time > 1000 ? 1000 : self._time)
}
else{
self.hide()
}
},
_reset:function(){
var self = this, _class = self.constructor, noMask = true;
if(this._iframe){
this._iframe.remove()
}
component.exports._reset.call(this);
component.destroy(self.main);
Nui.each(_class.__instances, function(val){
if(val && val._options.isMask === true && val !== self && val._containerDOM === self._containerDOM){
return (noMask = false);
}
});
if(noMask && self._containerDOM.__layermask__){
self._containerDOM.__layermask__.remove();
self._containerDOM.__layermask__ = null;
}
if(self._options.timer > 0){
self.timer = 0;
clearTimeout(self._timerid);
}
},
reset:function(){
if(this._callback('ResetBefore') !== false){
this.option(true)
this._callback('Reset')
}
return this;
},
resize:function(){
var self = this, opts = self._options, element = self.element;
self._resize();
self._callback('Resize');
return self
},
hide:function(){
if(this._options.isHide === true){
if(this._callback('HideBefore') === false){
return
}
this.destroy()
}
},
destroy:function(){
var self = this, _class = self.constructor, opts = self._options;
if(self._callback('DestroyBefore') === false){
return
}
self._delete();
self._reset();
self._setLower(true);
if(!self._isdestroy){
_class._zIndex--;
self._isdestroy = true;
}
self._callback('Destroy');
}
})
});