lu2
Version:
Simple and flexible UI component library based on native HTML and JavaScript
1,119 lines (945 loc) • 38.9 kB
JavaScript
/**
* @Drop.js
* @author zhangxinxu
* @version
* Created: 15-06-30
*/
/* global module */
(function (global, factory) {
if (typeof exports === 'object' && typeof module !== 'undefined') {
global.Follow = require('./Follow');
module.exports = factory();
} else if (typeof define === 'function' && (define.amd || define.cmd)) {
define(factory);
} else {
global.Drop = factory();
}
// eslint-disable-next-line
}((typeof global !== 'undefined') ? global
// eslint-disable-next-line
: ((typeof window !== 'undefined') ? window
: ((typeof self !== 'undefined') ? self : this)), function (require) {
var Follow = (this || self).Follow;
if (typeof require == 'function' && !Follow) {
Follow = require('common/ui/Follow');
} else if (!Follow) {
window.console.error('need Follow.js');
return {};
}
/**
* 实例方法
* @param {Object} trigger 触发元素,$()包装器元素类型
* @param {Object} target 显示的浮动定位元素,$()包装器元素类型
* @param {Object} options 可选参数
*/
var Drop = function (eleTrigger, eleTarget, options) {
this.init(eleTrigger, eleTarget, options);
return this;
};
/**
* Drop 初始化方法
* @date 2019-10-28
* @param {Object} trigger 触发元素,$()包装器元素类型
* @param {Object} target 显示的浮动定位元素,$()包装器元素类型
* @param {Object} options 可选参数
*/
Drop.prototype.init = function (eleTrigger, eleTarget, options) {
if (typeof eleTrigger == 'string') {
eleTrigger = document.getElementById(eleTrigger) || document.querySelector(eleTrigger);
}
if (typeof eleTarget == 'string') {
eleTarget = document.getElementById(eleTarget) || document.querySelector(eleTarget);
}
if (eleTarget && typeof eleTarget == 'object' && typeof eleTarget.nodeType != 'number') {
options = eleTarget;
eleTarget = null;
}
var defaults = {
// 触发元素显示的事件,‘null’直接显示;‘hover’是hover方法;‘click’是点击显示;其他为手动显示与隐藏。
eventType: 'null',
offsets: {
x: 0,
y: 0
},
position: '7-5',
selector: '',
edgeAdjust: true,
onShow: function () { },
onHide: function () { }
};
options = options || {};
for (var key in defaults) {
if (typeof options[key] == 'undefined' && eleTrigger) {
var strAttr = eleTrigger.getAttribute('data-' + key.toLowerCase());
if (strAttr !== null) {
if (key == 'edgeAdjust' && strAttr == 'false') {
options[key] = false;
} else if (key == 'offsets') {
var arrOffsets = strAttr.split(/,|\s+/);
var objOffsets = {
x: Number(arrOffsets[0].trim()) || 0,
y: Number(arrOffsets[1].trim()) || 0
};
options[key] = objOffsets;
} else {
options[key] = strAttr;
}
}
}
}
var objParams = Object.assign({}, defaults, options || {});
// 元素暴露给实例
this.element = {
trigger: eleTrigger,
target: eleTarget
};
// 回调
this.callback = {
show: objParams.onShow,
hide: objParams.onHide
};
// 暴露参数
this.params = {
// 事件类型
eventType: objParams.eventType,
// 偏移
offsets: objParams.offsets,
// 位置
position: objParams.position,
// 选择器
selector: objParams.selector,
// 边缘调整
edgeAdjust: objParams.edgeAdjust
};
// 实例的显示状态
this.display = false;
if (!eleTarget || !eleTrigger) {
return this;
}
// 事件绑定处理
this.events();
// 存储实例对象
if (!eleTrigger.data) {
eleTrigger.data = {};
}
eleTrigger.data.drop = this;
return this;
};
/**
* 下拉定位的事件处理
* @return {[type]} [description]
*/
Drop.prototype.events = function () {
// 元素
var eleTrigger = this.element.trigger;
var eleTarget = this.element.target;
// 参数
var objParams = this.params;
// 获取匹配选择器的eleTrigger子元素
var funGetClosestChild = function (element) {
if (!objParams.selector) {
return null;
}
var eleClosestSelector = element.closest(objParams.selector);
if (eleTrigger.contains(eleClosestSelector) == false) {
return null;
}
return eleClosestSelector;
};
// 根据不同事件类型进行逻辑处理
switch (objParams.eventType) {
// 默认值,直接显示
case 'null': {
this.show();
break;
}
case 'hover': {
// hover处理需要增加延时
var timerHover;
// 同时,从trigger移动到target也需要延时,
// 因为两者可能有间隙,不能单纯移出就隐藏
var timerHold;
// 事件走起
eleTrigger.addEventListener('mouseover', function (event) {
// 不是在元素自身移动
if (event.relatedTarget !== event.target) {
// 委托查询
var eleClosestSelector = funGetClosestChild(event.target);
// 如果走委托
if (eleClosestSelector) {
// 改变trigger元素
this.element.trigger = eleClosestSelector;
}
// 显示定时器
if (!objParams.selector || eleClosestSelector) {
// 显示的定时器
timerHover = setTimeout(function () {
this.show();
}.bind(this), 150);
// 去除隐藏的定时器
clearTimeout(timerHold);
}
}
}.bind(this));
eleTrigger.addEventListener('mouseleave', function () {
// 清除显示的定时器
clearTimeout(timerHover);
// 隐藏的定时器
timerHold = setTimeout(function () {
this.hide();
}.bind(this), 200);
}.bind(this));
if (!eleTarget.isBindDropHover) {
eleTarget.addEventListener('mouseenter', function () {
// 去除隐藏的定时器
clearTimeout(timerHold);
});
eleTarget.addEventListener('mouseleave', function () {
// 隐藏
timerHold = setTimeout(function () {
this.hide();
}.bind(this), 100);
}.bind(this));
eleTarget.isBindDropHover = true;
}
// 键盘支持,原本使用focus事件,但并不利于键盘交互
eleTrigger.addEventListener('click', function (event) {
// window.isKeyEvent表示是否键盘触发,来自Keyboard.js
if (!window.isKeyEvent) {
return;
}
event.preventDefault();
var eleClosestSelector = funGetClosestChild(event.target);
// 如果走委托
if (eleClosestSelector) {
// 改变trigger元素
this.element.trigger = eleClosestSelector;
}
// 显示定时器
if (!objParams.selector || eleClosestSelector) {
// 点击即显示
if (this.display == false) {
this.show();
} else {
this.hide();
}
}
}.bind(this));
break;
}
// 点击或者右键
case 'click': case 'contextmenu': {
eleTrigger.addEventListener(objParams.eventType, function (event) {
event.preventDefault();
// aria支持
// 获得委托的选择器匹配元素
var eleClosestSelector = funGetClosestChild(event.target);
if (eleClosestSelector) {
// 改变trigger元素
this.element.trigger = eleClosestSelector;
}
// 点击即显示
if (!objParams.selector || eleClosestSelector) {
// 重复右键点击一直显示,非显隐切换
if (objParams.eventType == 'contextmenu') {
objParams.position = [event.pageX, event.pageY];
this.show();
return;
}
if (this.display == false) {
this.show();
} else {
this.hide();
}
}
}.bind(this));
break;
}
}
// 点击页面空白区域隐藏
document.addEventListener('mouseup', function (event) {
var eleClicked = event && event.target;
if (!eleClicked || this.display != true) {
return;
}
// 因为trigger和target可能动态变化
// 因此这里再次获取一遍
var eleTrigger = this.element.trigger;
var eleTarget = this.element.target;
if (!eleTarget || !eleTrigger) {
return;
}
if (eleTrigger.contains(eleClicked) == false && eleTarget.contains(eleClicked) == false) {
this.hide();
}
}.bind(this));
// 窗体尺寸改变生活的重定位
window.addEventListener('resize', function () {
this.follow();
}.bind(this));
};
/**
* 下拉定位处理
* @return {Object} 返回当前实例对象
*/
Drop.prototype.follow = function () {
var eleTrigger = this.element.trigger;
var eleTarget = this.element.target;
// 下拉必须是显示状态才执行定位处理
if (this.display == true && window.getComputedStyle(eleTrigger).display != 'none') {
new Follow(eleTrigger, eleTarget, {
offsets: this.params.offsets,
position: this.params.position,
edgeAdjust: this.params.edgeAdjust
});
}
return this;
};
/**
* 下拉的显示处理
* @return {Object} 返回当前实例对象
*/
Drop.prototype.show = function () {
// target需要在页面中
var eleTrigger = this.element.trigger;
var eleTarget = this.element.target;
// 如果target在内存中,append到页面上
if (eleTarget && document.body.contains(eleTarget) == false) {
document.body.appendChild(eleTarget);
}
// 改变显示标志量
this.display = true;
// 进行定位
eleTarget.style.position = 'absolute';
eleTarget.style.display = 'inline';
// 键盘ESC隐藏支持
eleTarget.classList.add('ESC');
var strId = eleTarget.id;
if (!strId) {
strId = ('lulu_' + Math.random()).replace('0.', '');
eleTarget.id = strId;
}
eleTrigger.setAttribute('data-target', strId);
// aria
eleTrigger.setAttribute('aria-expanded', 'true');
// 定位
this.follow();
// 显示回调处理
if (typeof this.callback.show == 'function') {
this.callback.show.call(this, eleTrigger, eleTarget);
}
return this;
};
/**
* 下拉的隐藏处理
* @return {Object} 返回当前实例对象
*/
Drop.prototype.hide = function () {
var eleTrigger = this.element.trigger;
var eleTarget = this.element.target;
// 隐藏下拉面板
eleTarget.style.display = 'none';
eleTarget.classList.remove('ESC');
// aria
eleTrigger.setAttribute('aria-expanded', 'false');
if (window.isKeyEvent) {
eleTrigger.focus();
}
// 更改显示标志量
this.display = false;
// 隐藏回调处理
if (typeof this.callback.hide == 'function') {
this.callback.hide.call(this, eleTrigger, eleTarget);
}
return this;
};
/**
* drop 拓展list
* @date 2019-11-01
* @returns {object} 返回当前实例对象
* 兼容以下几种语法
* new Drop().list(eleTrigger, data);
* new Drop().list(eleTrigger, data, options);
* new Drop(eleTrigger).list(data, options);
* new Drop(eleTrigger, options).list(data);
*/
Drop.prototype.list = function (eleTrigger, data, options) {
// 基于类型进行参数判断
[].slice.call(arguments).forEach(function (argument) {
var strTypeArgument = typeof argument;
if (strTypeArgument == 'string') {
eleTrigger = document.querySelector(argument);
} else if (strTypeArgument == 'function') {
data = argument;
} else if (strTypeArgument == 'object') {
if (typeof argument.nodeType == 'number') {
eleTrigger = argument;
} else if (argument.map) {
data = argument;
} else {
options = argument;
}
}
});
if (eleTrigger && typeof eleTrigger.nodeType != 'number') {
eleTrigger = null;
}
eleTrigger = eleTrigger || this.element.trigger;
// 触发元素和数据是必须项
if (!eleTrigger || !data) {
return this;
}
// 如果已经初始化就不用初始化了
if (eleTrigger.data && eleTrigger.data.drop) {
return eleTrigger.data.drop;
}
var defaults = {
// 触发元素显示的事件,‘null’直接显示;‘hover’是hover方法;‘click’是点击显示;其他为手动显示与隐藏。
eventType: 'click',
offsets: {
x: 0,
y: 0
},
position: '4-1',
selector: '',
width: '',
onShow: function () { },
onHide: function () { },
// this为当前点击的列表元素,支持两个参数,第一个参数为列表元素对应的数据(纯对象),第二个是当前实例对象
onSelect: function () { }
};
// Drop 配置
var objParams = Object.assign({}, defaults, options || {});
// 一些常量
var SELECTED = 'selected';
var DISABLED = 'disabled';
// ui类名
// 类名变量
// 样式类名统一处理
var CL = {
add: function () {
return ['ui-droplist'].concat([].slice.call(arguments)).join('-');
},
toString: function () {
return 'ui-droplist';
}
};
// trigger元素赋值的方法
var strMethod = 'innerHTML';
if (eleTrigger.matches('input')) {
strMethod = 'value';
}
// 存储原始参数值
this.data = data;
// 列表渲染需要的数组项
var arrListData = data;
if (typeof data == 'function') {
arrListData = data();
}
// 初始的匹配和默认索引值获取(如果没有设置selected选项)
// 匹配的索引值
var strMatchIndex = '-1';
// 是否默认包含选中项
var isSomeItemSelected = false;
// target元素创建
var eleTarget = document.createElement('div');
eleTarget.setAttribute('role', 'listbox');
eleTarget.setAttribute('tabindex', '-1');
// 宽度处理
if (/^\d+$/.test(objParams.width)) {
eleTarget.style.width = objParams.width + 'px';
} else {
eleTarget.style.width = objParams.width;
}
eleTarget.className = CL.add('x');
// 遍历数据
// 目的是获得匹配索引,和改变默认值(如果有设置selected选项)
// 由于数据可能无限嵌套,因此走递归
var funRecursion = function (arrData, arrIndex) {
if (!arrData || !arrData.length) {
return;
}
arrData.forEach(function (objData, numIndex) {
// 此时数组项的索引深度
var arrCurrentIndex = arrIndex.concat(numIndex);
// 多级数据结构
if (objData && objData.data) {
funRecursion(objData.data, arrCurrentIndex);
return;
}
if (objData && objData[SELECTED] && !objData[DISABLED] && objData.value) {
eleTrigger[strMethod] = objData.value;
// 找到设置了selected的选项,并记住索引
strMatchIndex = arrCurrentIndex.join('-');
}
// 修改全局判断,这样,eleTrigger无需
// 再根据本身内容确定默认的选中项了
if (objData && objData[SELECTED]) {
isSomeItemSelected = true;
}
});
};
funRecursion(arrListData, []);
// 此时trigger元素内部的内容
var strTrigger = (eleTrigger[strMethod] || '').trim();
// 根据eleTrigger的内容信息确定哪个数据是selected
// 遍历数据
if (isSomeItemSelected == false && strTrigger) {
funRecursion = function (arrData, arrIndex) {
if (!arrData || !arrData.length) {
return;
}
arrData.forEach(function (objData, numIndex) {
// 此时数组项的索引深度
var arrCurrentIndex = arrIndex.concat(numIndex);
// 多级数据结构
if (objData && objData.data) {
funRecursion(objData.data, arrCurrentIndex);
return;
}
// 如果有匹配,设置为选中
if (typeof objData.value == 'string' && objData.value.trim() == strTrigger) {
strMatchIndex = arrCurrentIndex.join('-');
// 设置为选中
objData[SELECTED] = true;
}
});
};
funRecursion(arrListData, []);
}
// 列表绘制渲染方法
// 每次show的时候都执行刷新
var funRender = function (eleTarget, arrListData) {
if (typeof arrListData == 'function') {
arrListData = arrListData();
}
// 没有数据时候的处理
if (!arrListData || arrListData.length == 0) {
arrListData = [{
value: '没有数据',
disabled: true
}];
}
// 是否包含选中项
var isSomeItemSelected = arrListData.some(function (objData) {
return objData && objData[SELECTED];
});
// 列表数据更新
eleTarget.innerHTML = (function () {
var strHtml = '';
var funStep = function (arrData, arrIndex) {
var strHtmlStep = '';
arrData.forEach(function (objData, numIndex) {
// 为空数据作为分隔线
if (objData == '-' || objData === null || JSON.stringify(objData) == '{}') {
strHtmlStep += '<hr class="' + CL.add('hr') + '">';
return;
}
// 此时数组项的索引深度
var arrCurrentIndex = arrIndex.concat(numIndex);
// 一些属性值
var strAttrHref = objData.href || 'javascript:';
// target属性
var strAttrTarget = '';
if (objData.target) {
strAttrTarget = ' target="' + objData.target + '"';
}
// 类名
var strAttrClass = CL.add('li');
if (objData[SELECTED]) {
strAttrClass = strAttrClass + ' ' + SELECTED;
}
// 是否包含子项
var strAttrSublist = '';
if (objData.data) {
strAttrSublist = ' data-sublist';
}
// label标记
var strAttrLabel = '';
if (objData.label) {
strAttrLabel = ' aria-label="' + objData.label + '"';
}
// 如果数据不含选中项,使用存储的索引值进行匹配
if (isSomeItemSelected == false && strMatchIndex == arrCurrentIndex.join('-')) {
objData[SELECTED] = true;
}
// 禁用态和非禁用使用标签区分
// 如果想要支持多级,data-index值可以"1-2"这样
if (objData[DISABLED] != true) {
strHtmlStep += '<a href="' + strAttrHref + '"' + strAttrTarget + strAttrLabel + ' class="' + strAttrClass + '" data-index="' + arrCurrentIndex.join('-') + '" role="option" aria-selected="' + (objData[SELECTED] || 'false') + '" ' + strAttrSublist + '>' + objData.value + '</a>';
if (objData.data) {
strHtmlStep += '<div class="' + CL.add('xx') + '"><div class="' + CL.add('x') + '" role="listbox">' + funStep(objData.data, arrCurrentIndex) + '</div></div>';
}
} else {
strHtmlStep += '<span class="' + strAttrClass + '"' + strAttrLabel + '>' + objData.value + '</span>';
}
});
return strHtmlStep;
};
strHtml += funStep(arrListData, []);
return strHtml;
})();
// 存储在DOM对象上,给回调使用
eleTarget.listData = arrListData;
};
// 重新初始化 drop
this.init(eleTrigger, eleTarget, {
eventType: objParams.eventType,
offsets: objParams.offsets,
selector: objParams.selector,
position: objParams.position,
onShow: function () {
funRender.call(this, eleTarget, this.data);
objParams.onShow.apply(this, arguments);
},
onHide: objParams.onHide
});
// 绑定事件
eleTarget.addEventListener('click', function (event) {
// IE可能是文件节点
if (event.target.nodeType != 1 || !event.target.closest) {
return;
}
// 目标点击元素
var eleClicked = event.target.closest('a');
// 未获取到元素返回
if (!eleClicked) {
return;
}
// 当前列表显示使用的数据
var arrListData = eleTarget.listData;
// 如果是多级嵌套列表,这里需要额外处理
var strIndex = eleClicked.getAttribute('data-index');
if (!strIndex) {
return;
}
// 根据点击的元素索引获取对应的数据对象
var objItemData = null;
strIndex.split('-').forEach(function (numIndex) {
if (objItemData === null) {
objItemData = arrListData[numIndex];
} else if (objItemData.data) {
objItemData = objItemData.data[numIndex];
} else {
objItemData = objItemData[numIndex];
}
});
// 如果这里返回,说明数据有问题
// 或者代码逻辑有bug
if (!objItemData) {
return;
}
// 点击包含下级数据的列表
if (typeof eleClicked.getAttribute('data-sublist') == 'string') {
eleClicked.classList.add(SELECTED);
// 此时显示的下级列表元素
var eleSubTarget = eleClicked.nextElementSibling.querySelector('.' + CL.add('x'));
if (!eleSubTarget) {
return;
}
var objBounding = eleSubTarget.getBoundingClientRect();
// 水平方向是方向变化
// 交给CSS控制
if (objBounding.right > window.innerWidth) {
eleSubTarget.classList.add('reverse');
} else {
eleSubTarget.classList.remove('reverse');
}
// 垂直方向偏移
var offsetTop = 0;
if (objBounding.bottom > window.innerHeight) {
offsetTop = window.innerHeight - objBounding.bottom;
}
eleSubTarget.style.msTransform = 'translateY(' + offsetTop + 'px)';
eleSubTarget.style.transform = 'translateY(' + offsetTop + 'px)';
return;
}
// 改变选中索引
if (strIndex != strMatchIndex) {
var objLastItemData = null;
if (strMatchIndex != '-1') {
strMatchIndex.split('-').forEach(function (numIndex) {
if (objLastItemData === null) {
objLastItemData = arrListData[numIndex];
} else if (objLastItemData.data) {
objLastItemData = objLastItemData.data[numIndex];
} else {
objLastItemData = objLastItemData[numIndex];
}
});
if (objLastItemData) {
delete objLastItemData[SELECTED];
}
}
// 设置为true
objItemData[SELECTED] = true;
// 更新匹配索引
strMatchIndex = strIndex;
}
// 触发用户自定义选择事件
objParams.onSelect.call(this, objItemData, eleClicked);
// 不是鼠标右击事件,也不是委托模式更新
if (objParams.eventType != 'contextmenu' && objParams.selector == '' && !objItemData.href) {
eleTrigger[strMethod] = objItemData.value;
}
// 隐藏
this.hide();
}.bind(this));
// hover时候次级列表也显示
eleTarget.addEventListener('mouseover', function (event) {
// IE可能是文件节点
if (event.target.nodeType != 1 || !event.target.closest) {
return;
}
var eleHovered = event.target.closest('a');
if (!eleHovered) {
return;
}
var eleItemSublist = eleHovered.parentElement.querySelector('.' + SELECTED + '[data-sublist]');
if (eleItemSublist && eleItemSublist != eleHovered) {
eleItemSublist.classList.remove(SELECTED);
}
if (eleHovered.classList.contains(SELECTED) == false && typeof eleHovered.getAttribute('data-sublist') == 'string') {
eleHovered.click();
}
});
return this;
};
/**
* drop 拓展panel
* @date 2019-11-01
* 兼容以下两种语法
* new Drop().panel(eleTrigger, options);
* new Drop(eleTrigger).panel(options);
* @returns {object} 返回当前实例对象
*/
Drop.prototype.panel = function (eleTrigger, options) {
// 不同类型参数的处理
if (arguments.length === 2) {
eleTrigger = arguments[0];
options = arguments[1];
} else if (arguments.length === 1) {
options = arguments[0];
eleTrigger = null;
}
if (typeof eleTrigger == 'string') {
eleTrigger = document.querySelector(eleTrigger);
}
eleTrigger = eleTrigger || this.element.trigger;
if (!eleTrigger) {
return this;
}
// 如果已经初始化就不用初始化了
if (eleTrigger.data && eleTrigger.data.drop) {
return eleTrigger.data.drop;
}
var defaults = {
title: '',
content: '',
buttons: [{}, {}],
width: 'auto',
eventType: 'click',
selector: '',
offsets: {
x: 0,
y: 0
},
position: '4-1',
onShow: function () { },
onHide: function () { }
};
// Drop 配置
var objParams = Object.assign({}, defaults, options || {});
// 关闭SVG
var SVG = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><path d="M116.152,99.999l36.482-36.486c2.881-2.881,2.881-7.54,0-10.42 l-5.215-5.215c-2.871-2.881-7.539-2.881-10.42,0l-36.484,36.484L64.031,47.877c-2.881-2.881-7.549-2.881-10.43,0l-5.205,5.215 c-2.881,2.881-2.881,7.54,0,10.42l36.482,36.486l-36.482,36.482c-2.881,2.881-2.881,7.549,0,10.43l5.205,5.215 c2.881,2.871,7.549,2.871,10.43,0l36.484-36.488L137,152.126c2.881,2.871,7.549,2.871,10.42,0l5.215-5.215 c2.881-2.881,2.881-7.549,0-10.43L116.152,99.999z"/></svg>';
// ui类名
// 类名变量
// 样式类名统一处理
var CL = {
add: function () {
return ['ui-dropanel'].concat([].slice.call(arguments)).join('-');
},
toString: function () {
return 'ui-dropanel';
}
};
// 面板容器
var elePanel = document.createElement('div');
elePanel.className = CL.add('x');
// 面板的宽度设置
// 如果纯数值,认为是px长度
if (/^\d+$/.test(objParams.width)) {
elePanel.style.width = objParams.width + 'px';
} else if (/^\d+\D+$/.test(objParams.width)) {
elePanel.style.width = objParams.width;
}
// 创建轻弹框面板的各个元素
// title
var eleTitle = document.createElement('h5');
eleTitle.className = CL.add('title');
eleTitle.innerHTML = objParams.title;
// close button
var eleClose = document.createElement('button');
eleClose.setAttribute('aria-label', '关闭');
eleClose.innerHTML = SVG;
eleClose.className = CL.add('close');
// content
var eleContent = document.createElement('content');
eleContent.className = CL.add('content');
eleContent.innerHTML = objParams.content;
// footer
var eleFooter = document.createElement('div');
eleFooter.className = CL.add('footer');
// 组装
elePanel.appendChild(eleTitle);
elePanel.appendChild(eleClose);
elePanel.appendChild(eleContent);
elePanel.appendChild(eleFooter);
// 初始化
this.init(eleTrigger, elePanel, {
eventType: objParams.eventType,
offsets: objParams.offsets,
// 实现点击或hover事件的委托实现
selector: objParams.selector,
position: objParams.position,
onShow: objParams.onShow,
onHide: objParams.onHide
});
// 重新添加element
Object.assign(this.element, {
panel: elePanel,
title: eleTitle,
close: eleClose,
content: eleContent,
footer: eleFooter
});
// 绑定事件
// 关闭事件
eleClose.addEventListener('click', function () {
this.hide();
}.bind(this), false);
// 按钮
objParams.buttons.forEach(function (objBtn, numIndex) {
// 避免btn为null等值报错
objBtn = objBtn || {};
// 按钮的默认参数
var strType = objBtn.type || '';
if (!strType && numIndex == 0) {
strType = 'danger';
}
var strValue = objBtn.value;
if (!strValue) {
strValue = ['确定', '取消'][numIndex];
}
// 如果没有指定事件,则认为是关闭行为
var objEvents = objBtn.events || {
click: function () {
this.hide();
}.bind(this)
};
// 如果没有指定事件类型,直接是函数
// 则认为是点击事件
if (typeof objEvents == 'function') {
objEvents = {
click: objEvents
};
}
var eleBtn = null;
// 普通按钮
if (!objBtn['for']) {
eleBtn = document.createElement('button');
this.element['button' + numIndex] = eleBtn;
} else {
eleBtn = document.createElement('label');
eleBtn.setAttribute('for', objBtn['for']);
eleBtn.setAttribute('role', 'button');
}
// 按钮的文案
eleBtn.innerHTML = strValue;
// 按钮类名
eleBtn.className = String(CL).replace('dropanel', 'button') + ' ' + CL.add('button') + ' ' + (objBtn.className || '');
// 按钮的类型
if (strType) {
eleBtn.setAttribute('data-type', strType);
}
this.element['button' + numIndex] = eleBtn;
for (var strEventType in objEvents) {
eleBtn.addEventListener(strEventType, function (event) {
event.drop = this;
objEvents[strEventType](event);
}.bind(this), false);
}
this.element.footer.appendChild(eleBtn);
}.bind(this));
return this;
};
// is-drop 属性下的快捷语法
var funAutoInitAndWatching = function () {
var strSelector = '[is-drop]';
// 同步更新分页内容的方法
var funSyncRefresh = function (nodes) {
if (!nodes || !nodes.forEach) {
return;
}
nodes.forEach(function (node) {
if (node.nodeType !== 1) {
return;
}
var attrDrop = node.getAttribute('is-drop');
var objOption = {
eventType: node.getAttribute('data-eventtype') || 'click'
};
var objDrop = null;
if (attrDrop) {
objDrop = new Drop(node, attrDrop, objOption);
} else {
objDrop = new Drop(node, objOption);
}
node.dispatchEvent(new CustomEvent('connected', {
detail: {
drop: objDrop
}
}));
});
};
// 所有 is-drop 元素初始设置
funSyncRefresh(document.querySelectorAll(strSelector));
if (window.watching === false) {
return;
}
// DOM Insert检测自动初始化
// IE11+使用MutationObserver
// IE9-IE10使用Mutation Events
if (window.MutationObserver) {
var observerSelect = new MutationObserver(function (mutationsList) {
mutationsList.forEach(function (mutation) {
if (mutation.type == 'childList') {
mutation.addedNodes.forEach(function (eleAdd) {
if (eleAdd.matches && eleAdd.matches(strSelector)) {
funSyncRefresh([eleAdd]);
} else if (eleAdd.querySelector) {
funSyncRefresh(eleAdd.querySelectorAll(strSelector));
}
});
}
});
});
observerSelect.observe(document.body, {
childList: true,
subtree: true
});
} else {
document.body.addEventListener('DOMNodeInserted', function (event) {
// 插入节点
funSyncRefresh([event.target]);
});
}
};
// 监听-免初始绑定
if (document.readyState != 'loading') {
funAutoInitAndWatching();
} else {
window.addEventListener('DOMContentLoaded', funAutoInitAndWatching);
}
return Drop;
}));