UNPKG

hexo-theme-nexmoe

Version:
1,705 lines (1,455 loc) 240 kB
/* ! * mdui v0.4.3 (https://mdui.org) * Copyright 2016-2019 zdhxiong * Licensed under MIT */ /* jshint ignore:start */ (function(global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.mdui = factory(); }(this, () => { /* jshint ignore:end */ const mdui = {}; /** * ============================================================================= * ************ 浏览器兼容性问题修复 ************ * ============================================================================= */ /** * requestAnimationFrame * cancelAnimationFrame */ (function() { let lastTime = 0; if (!window.requestAnimationFrame) { window.requestAnimationFrame = window.webkitRequestAnimationFrame; window.cancelAnimationFrame = window.webkitCancelAnimationFrame; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { const currTime = new Date().getTime(); const timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); const id = window.setTimeout(() => { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } }()); /** * JQ 1.0.0 (https://github.com/zdhxiong/mdui.JQ#readme) * Copyright 2018-2018 zdhxiong * Licensed under MIT */ const $ = (function() { const JQ = function JQ(arr) { const self = this; for (let i = 0; i < arr.length; i += 1) { self[i] = arr[i]; } self.length = arr.length; return this; }; function $(selector) { const arr = []; if (!selector) { return new JQ(arr); } if (selector instanceof JQ) { return selector; } if (typeof selector === 'string') { const html = selector.trim(); if (html[0] === '<' && html[html.length - 1] === '>') { // 创建 HTML 字符串 let toCreate = 'div'; if (html.indexOf('<li') === 0) { toCreate = 'ul'; } if (html.indexOf('<tr') === 0) { toCreate = 'tbody'; } if (html.indexOf('<td') === 0 || html.indexOf('<th') === 0) { toCreate = 'tr'; } if (html.indexOf('<tbody') === 0) { toCreate = 'table'; } if (html.indexOf('<option') === 0) { toCreate = 'select'; } const tempParent = document.createElement(toCreate); tempParent.innerHTML = html; for (let i = 0; i < tempParent.childNodes.length; i += 1) { arr.push(tempParent.childNodes[i]); } } else { // 选择器 const elems = selector[0] === '#' && !selector.match(/[ .<>:~]/) ? [document.getElementById(selector.slice(1))] : document.querySelectorAll(selector); for (let i$1 = 0; i$1 < elems.length; i$1 += 1) { if (elems[i$1]) { arr.push(elems[i$1]); } } } } else if (typeof selector === 'function') { // function return $(document).ready(selector); } else if (selector.nodeType || selector === window || selector === document) { // Node arr.push(selector); } else if (selector.length > 0 && selector[0].nodeType) { // NodeList for (let i$2 = 0; i$2 < selector.length; i$2 += 1) { arr.push(selector[i$2]); } } return new JQ(arr); } $.fn = JQ.prototype; function extend() { const this$1 = this; const args = []; let len = arguments.length; while (len--) args[len] = arguments[len]; if (!args.length) { return this; } // $.extend(obj) if (args.length === 1) { Object.keys(args[0]).forEach(prop => { this$1[prop] = args[0][prop]; }); return this; } // $.extend({}, defaults[, obj]) const target = args.shift(); const loop = function(i) { Object.keys(args[i]).forEach(prop => { target[prop] = args[i][prop]; }); }; for (let i = 0; i < args.length; i += 1) loop(i); return target; } $.fn.extend = extend; $.extend = extend; /** * 判断一个节点名 * @param ele * @param name * @returns {boolean} */ function isNodeName(ele, name) { return ele.nodeName && ele.nodeName.toLowerCase() === name.toLowerCase(); } /** * 除去 null 后的 object 类型 * @param obj * @returns {*|boolean} */ function isObjectLike(obj) { return typeof obj === 'object' && obj !== null; } function isFunction(fn) { return typeof fn === 'function'; } function isString(obj) { return typeof obj === 'string'; } function isWindow(win) { return win && win === win.window; } function isDocument(doc) { return doc && doc.nodeType === doc.DOCUMENT_NODE; } function isArrayLike(obj) { return typeof obj.length === 'number'; } /** * 循环数组或对象 * @param obj * @param callback * @returns {*} */ function each(obj, callback) { if (isArrayLike(obj)) { for (let i = 0; i < obj.length; i += 1) { if (callback.call(obj[i], i, obj[i]) === false) { return obj; } } } else { const keys = Object.keys(obj); for (let i$1 = 0; i$1 < keys.length; i$1 += 1) { if (callback.call(obj[keys[i$1]], keys[i$1], obj[keys[i$1]]) === false) { return obj; } } } return obj; } /** * 遍历数组或对象,通过函数返回一个新的数组或对象,null 和 undefined 将被过滤掉。 * @param elems * @param callback * @returns {Array} */ function map(elems, callback) { let ref, value; const ret = []; each(elems, (i, elem) => { value = callback(elem, i); if (value !== null && value !== undefined) { ret.push(value); } }); return (ref = []).concat.apply(ref, ret); } /** * 把对象合并到第一个参数中,并返回第一个参数 * @param first * @param second * @returns {*} */ function merge(first, second) { each(second, (i, val) => { first.push(val); }); return first; } /** * 删除数组中重复元素 * @param arr {Array} * @returns {Array} */ function unique(arr) { const result = []; for (let i = 0; i < arr.length; i += 1) { if (result.indexOf(arr[i]) === -1) { result.push(arr[i]); } } return result; } const elementDisplay = {}; /** * 获取元素的默认 display 样式值,用于 .show() 方法 * @param nodeName * @returns {*} */ function defaultDisplay(nodeName) { let element, display; if (!elementDisplay[nodeName]) { element = document.createElement(nodeName); document.body.appendChild(element); display = getComputedStyle(element, '').getPropertyValue('display'); element.parentNode.removeChild(element); if (display === 'none') { display = 'block'; } elementDisplay[nodeName] = display; } return elementDisplay[nodeName]; } $.extend({ each: each, merge: merge, unique: unique, map: map, /** * 一个 DOM 节点是否包含另一个 DOM 节点 * @param parent {Node} 父节点 * @param node {Node} 子节点 * @returns {Boolean} */ contains: function contains(parent, node) { if (parent && !node) { return document.documentElement.contains(parent); } return parent !== node && parent.contains(node); }, /** * 将数组或对象序列化 * @param obj * @returns {String} */ param: function param(obj) { if (!isObjectLike(obj)) { return ''; } const args = []; function destructure(key, value) { let keyTmp; if (isObjectLike(value)) { each(value, (i, v) => { if (Array.isArray(value) && !isObjectLike(v)) { keyTmp = ''; } else { keyTmp = i; } destructure(key + '[' + keyTmp + ']', v); }); } else { if (value !== null && value !== '') { keyTmp = '=' + encodeURIComponent(value); } else { keyTmp = ''; } args.push(encodeURIComponent(key) + keyTmp); } } each(obj, (key, value) => { destructure(key, value); }); return args.join('&'); } }); $.fn.extend({ /** * 遍历对象 * @param callback {Function} * @return {JQ} */ each: function each$1(callback) { return each(this, callback); }, /** * 通过遍历集合中的节点对象,通过函数返回一个新的对象,null 或 undefined 将被过滤掉。 * @param callback {Function} * @returns {JQ} */ map: function map$1(callback) { return new JQ(map(this, (el, i) => { return callback.call(el, i, el); })); }, /** * 获取指定 DOM 元素,没有 index 参数时,获取所有 DOM 的数组 * @param index {Number=} * @returns {Node|Array} */ get: function get(index) { return index === undefined ? [].slice.call(this) : this[index >= 0 ? index : index + this.length]; }, /** * array中提取的方法。从start开始,如果end 指出。提取不包含end位置的元素。 * @param args {start, end} * @returns {JQ} */ slice: function slice() { const args = []; let len = arguments.length; while (len--) args[len] = arguments[len]; return new JQ([].slice.apply(this, args)); }, /** * 筛选元素集合 * @param selector {String|JQ|Node|Function} * @returns {JQ} */ filter: function filter(selector) { if (isFunction(selector)) { return this.map((index, ele) => { return selector.call(ele, index, ele) ? ele : undefined; }); } const $selector = $(selector); return this.map((index, ele) => { return $selector.index(ele) > -1 ? ele : undefined; }); }, /** * 从元素集合中删除指定的元素 * @param selector {String|Node|JQ|Function} * @return {JQ} */ not: function not(selector) { const $excludes = this.filter(selector); return this.map((index, ele) => { return $excludes.index(ele) > -1 ? undefined : ele; }); }, /** * 获取元素相对于 document 的偏移 * @returns {Object} */ offset: function offset() { if (this[0]) { const offset = this[0].getBoundingClientRect(); return { left: offset.left + window.pageXOffset, top: offset.top + window.pageYOffset, width: offset.width, height: offset.height }; } return null; }, /** * 返回最近的用于定位的父元素 * @returns {*|JQ} */ offsetParent: function offsetParent() { return this.map(function() { let parent = this.offsetParent; while (parent && $(parent).css('position') === 'static') { parent = parent.offsetParent; } return parent || document.documentElement; }); }, /** * 获取元素相对于父元素的偏移 * @return {Object} */ position: function position() { const self = this; if (!self[0]) { return null; } let offsetParent, offset; let parentOffset = { top: 0, left: 0 }; if (self.css('position') === 'fixed') { offset = self[0].getBoundingClientRect(); } else { offsetParent = self.offsetParent(); offset = self.offset(); if (!isNodeName(offsetParent[0], 'html')) { parentOffset = offsetParent.offset(); } parentOffset = { top: parentOffset.top + offsetParent.css('borderTopWidth'), left: parentOffset.left + offsetParent.css('borderLeftWidth') }; } return { top: offset.top - parentOffset.top - self.css('marginTop'), left: offset.left - parentOffset.left - self.css('marginLeft'), width: offset.width, height: offset.height }; }, /** * 显示指定元素 * @returns {JQ} */ show: function show() { return this.each(function() { if (this.style.display === 'none') { this.style.display = ''; } if (window.getComputedStyle(this, '').getPropertyValue('display') === 'none') { this.style.display = defaultDisplay(this.nodeName); } }); }, /** * 隐藏指定元素 * @returns {JQ} */ hide: function hide() { return this.each(function() { this.style.display = 'none'; }); }, /** * 切换元素的显示状态 * @returns {JQ} */ toggle: function toggle() { return this.each(function() { this.style.display = this.style.display === 'none' ? '' : 'none'; }); }, /** * 是否含有指定的 CSS 类 * @param className {String} * @returns {boolean} */ hasClass: function hasClass(className) { if (!this[0] || !className) { return false; } return this[0].classList.contains(className); }, /** * 移除指定属性 * @param attr {String} * @returns {JQ} */ removeAttr: function removeAttr(attr) { return this.each(function() { this.removeAttribute(attr); }); }, /** * 删除属性值 * @param name {String} * @returns {JQ} */ removeProp: function removeProp(name) { return this.each(function() { try { delete this[name]; } catch (e) { // empty } }); }, /** * 获取当前对象中第n个元素 * @param index {Number} * @returns {JQ} */ eq: function eq(index) { const ret = index === -1 ? this.slice(index) : this.slice(index, +index + 1); return new JQ(ret); }, /** * 获取对象中第一个元素 * @returns {JQ} */ first: function first() { return this.eq(0); }, /** * 获取对象中最后一个元素 * @returns {JQ} */ last: function last() { return this.eq(-1); }, /** * 获取一个元素的位置。 * 当 elem 参数没有给出时,返回当前元素在兄弟节点中的位置。 * 有给出了 elem 参数时,返回 elem 元素在当前对象中的位置 * @param elem {Selector|Node=} * @returns {Number} */ index: function index(elem) { if (!elem) { // 获取当前 JQ 对象的第一个元素在同辈元素中的位置 return this .eq(0) .parent() .children() .get() .indexOf(this[0]); } if (isString(elem)) { // 返回当前 JQ 对象的第一个元素在指定选择器对应的元素中的位置 return $(elem) .eq(0) .parent() .children() .get() .indexOf(this[0]); } // 返回指定元素在当前 JQ 对象中的位置 return this .get() .indexOf(elem); }, /** * 根据选择器、DOM元素或 JQ 对象来检测匹配元素集合, * 如果其中至少有一个元素符合这个给定的表达式就返回true * @param selector {String|Node|NodeList|Array|JQ|Window} * @returns boolean */ is: function is(selector) { const self = this[0]; if (!self || selector === undefined || selector === null) { return false; } if (isString(selector)) { if (self === document || self === window) { return false; } const matchesSelector = self.matches || self.matchesSelector || self.webkitMatchesSelector || self.mozMatchesSelector || self.oMatchesSelector || self.msMatchesSelector; return matchesSelector.call(self, selector); } if (selector === document || selector === window) { return self === selector; } if (selector.nodeType || isArrayLike(selector)) { const $compareWith = selector.nodeType ? [selector] : selector; for (let i = 0; i < $compareWith.length; i += 1) { if ($compareWith[i] === self) { return true; } } return false; } return false; }, /** * 根据 CSS 选择器找到后代节点的集合 * @param selector {String} * @returns {JQ} */ find: function find(selector) { const foundElements = []; this.each((i, _this) => { const nodeType = _this.nodeType; if (nodeType !== 1 && nodeType !== 9) { // 不是 element 和 document 则跳过 return; } merge(foundElements, _this.querySelectorAll(selector)); }); return new JQ(foundElements); }, /** * 找到直接子元素的元素集合 * @param selector {String=} * @returns {JQ} */ children: function children(selector) { const children = []; this.each((_, _this) => { each(_this.childNodes, (__, childNode) => { if (childNode.nodeType !== 1) { return; } if (!selector || (selector && $(childNode).is(selector))) { children.push(childNode); } }); }); return new JQ(unique(children)); }, /** * 保留含有指定子元素的元素,去掉不含有指定子元素的元素 * @param selector {String|Node|JQ|NodeList|Array} * @return {JQ} */ has: function has(selector) { const $targets = isString(selector) ? this.find(selector) : $(selector); const length = $targets.length; return this.filter(function() { for (let i = 0; i < length; i += 1) { if ($.contains(this, $targets[i])) { return true; } } return false; }); }, /** * 取得同辈元素的集合 * @param selector {String=} * @returns {JQ} */ siblings: function siblings(selector) { return this.prevAll(selector).add(this.nextAll(selector)); }, /** * 返回首先匹配到的父节点,包含父节点 * @param selector {String} * @returns {JQ} */ closest: function closest(selector) { let self = this; if (!self.is(selector)) { self = self.parents(selector).eq(0); } return self; }, /** * 删除所有匹配的元素 * @returns {JQ} */ remove: function remove() { return this.each((i, _this) => { if (_this.parentNode) { _this.parentNode.removeChild(_this); } }); }, /** * 添加匹配的元素到当前对象中 * @param selector {String|JQ} * @returns {JQ} */ add: function add(selector) { return new JQ(unique(merge(this.get(), $(selector)))); }, /** * 删除子节点 * @returns {JQ} */ empty: function empty() { return this.each(function() { this.innerHTML = ''; }); }, /** * 通过深度克隆来复制集合中的所有元素。 * (通过原生 cloneNode 方法深度克隆来复制集合中的所有元素。此方法不会有数据和事件处理程序复制到新的元素。这点和jquery中利用一个参数来确定是否复制数据和事件处理不相同。) * @returns {JQ} */ clone: function clone() { return this.map(function() { return this.cloneNode(true); }); }, /** * 用新元素替换当前元素 * @param newContent {String|Node|NodeList|JQ} * @returns {JQ} */ replaceWith: function replaceWith(newContent) { return this.before(newContent).remove(); }, /** * 将表单元素的值组合成键值对数组 * @returns {Array} */ serializeArray: function serializeArray() { const result = []; const elem = this[0]; if (!elem || !elem.elements) { return result; } $([].slice.call(elem.elements)).each(function() { const $elem = $(this); const type = $elem.attr('type'); if ( this.nodeName.toLowerCase() !== 'fieldset' && !this.disabled && ['submit', 'reset', 'button'].indexOf(type) === -1 && (['radio', 'checkbox'].indexOf(type) === -1 || this.checked) ) { result.push({ name: $elem.attr('name'), value: $elem.val() }); } }); return result; }, /** * 将表单元素或对象序列化 * @returns {String} */ serialize: function serialize() { const result = []; each(this.serializeArray(), (i, elem) => { result.push(encodeURIComponent(elem.name) + '=' + encodeURIComponent(elem.value)); }); return result.join('&'); } }); /** * val - 获取或设置元素的值 * @param value {String=} * @return {*|JQ} */ /** * html - 获取或设置元素的 HTML * @param value {String=} * @return {*|JQ} */ /** * text - 获取或设置元素的内容 * @param value {String=} * @return {*|JQ} */ each(['val', 'html', 'text'], (nameIndex, name) => { const props = { 0: 'value', 1: 'innerHTML', 2: 'textContent' }; const defaults = { 0: undefined, 1: undefined, 2: null }; $.fn[name] = function(value) { if (value === undefined) { // 获取值 return this[0] ? this[0][props[nameIndex]] : defaults[nameIndex]; } // 设置值 return this.each((i, elem) => { elem[props[nameIndex]] = value; }); }; }); /** * attr - 获取或设置元素的属性值 * @param {name|props|key,value=} * @return {String|JQ} */ /** * prop - 获取或设置元素的属性值 * @param {name|props|key,value=} * @return {String|JQ} */ /** * css - 获取或设置元素的样式 * @param {name|props|key,value=} * @return {String|JQ} */ each(['attr', 'prop', 'css'], (nameIndex, name) => { function set(elem, key, value) { if (nameIndex === 0) { elem.setAttribute(key, value); } else if (nameIndex === 1) { elem[key] = value; } else { elem.style[key] = value; } } function get(elem, key) { if (!elem) { return undefined; } if (nameIndex === 0) { return elem.getAttribute(key); } if (nameIndex === 1) { return elem[key]; } return window.getComputedStyle(elem, null).getPropertyValue(key); } $.fn[name] = function(key, value) { const argLength = arguments.length; if (argLength === 1 && isString(key)) { // 获取值 return get(this[0], key); } // 设置值 return this.each((i, elem) => { if (argLength === 2) { set(elem, key, value); } else { each(key, (k, v) => { set(elem, k, v); }); } }); }; }); /** * addClass - 添加 CSS 类,多个类名用空格分割 * @param className {String} * @return {JQ} */ /** * removeClass - 移除 CSS 类,多个类名用空格分割 * @param className {String} * @return {JQ} */ /** * toggleClass - 切换 CSS 类名,多个类名用空格分割 * @param className {String} * @return {JQ} */ each(['add', 'remove', 'toggle'], (nameIndex, name) => { $.fn[name + 'Class'] = function(className) { if (!className) { return this; } const classes = className.split(' '); return this.each((i, elem) => { each(classes, (j, cls) => { elem.classList[name](cls); }); }); }; }); /** * width - 获取元素的宽度 * @return {Number} */ /** * height - 获取元素的高度 * @return {Number} */ each({ Width: 'width', Height: 'height' }, (prop, name) => { $.fn[name] = function(val) { if (val === undefined) { // 获取 const elem = this[0]; if (isWindow(elem)) { return elem['inner' + prop]; } if (isDocument(elem)) { return elem.documentElement['scroll' + prop]; } const $elem = $(elem); // IE10、IE11 在 box-sizing:border-box 时,不会包含 padding 和 border,这里进行修复 let IEFixValue = 0; const isWidth = name === 'width'; if ('ActiveXObject' in window) { // 判断是 IE 浏览器 if ($elem.css('box-sizing') === 'border-box') { IEFixValue = parseFloat($elem.css('padding-' + (isWidth ? 'left' : 'top'))) + parseFloat($elem.css('padding-' + (isWidth ? 'right' : 'bottom'))) + parseFloat($elem.css('border-' + (isWidth ? 'left' : 'top') + '-width')) + parseFloat($elem.css('border-' + (isWidth ? 'right' : 'bottom') + '-width')); } } return parseFloat($(elem).css(name)) + IEFixValue; } // 设置 /* eslint no-restricted-globals: 0 */ if (!isNaN(Number(val)) && val !== '') { val += 'px'; } return this.css(name, val); }; }); /** * innerWidth - 获取元素的宽度,包含内边距 * @return {Number} */ /** * innerHeight - 获取元素的高度,包含内边距 * @return {Number} */ each({ Width: 'width', Height: 'height' }, (prop, name) => { $.fn['inner' + prop] = function() { let value = this[name](); const $elem = $(this[0]); if ($elem.css('box-sizing') !== 'border-box') { value += parseFloat($elem.css('padding-' + (name === 'width' ? 'left' : 'top'))); value += parseFloat($elem.css('padding-' + (name === 'width' ? 'right' : 'bottom'))); } return value; }; }); function dir(nodes, selector, nameIndex, node) { const ret = []; let elem; nodes.each((j, _this) => { elem = _this[node]; while (elem) { if (nameIndex === 2) { // prevUntil if (!selector || (selector && $(elem).is(selector))) { break; } ret.push(elem); } else if (nameIndex === 0) { // prev if (!selector || (selector && $(elem).is(selector))) { ret.push(elem); } break; } else if (!selector || (selector && $(elem).is(selector))) { // prevAll ret.push(elem); } elem = elem[node]; } }); return new JQ(unique(ret)); } /** * prev - 取得前一个匹配的元素 * @param selector {String=} * @return {JQ} */ /** * prevAll - 取得前面所有匹配的元素 * @param selector {String=} * @return {JQ} */ /** * prevUntil - 取得前面的所有元素,直到遇到匹配的元素,不包含匹配的元素 * @param selector {String=} * @return {JQ} */ each(['', 'All', 'Until'], (nameIndex, name) => { $.fn['prev' + name] = function(selector) { // prevAll、prevUntil 需要把元素的顺序倒序处理,以便和 jQuery 的结果一致 const $nodes = nameIndex === 0 ? this : $(this.get().reverse()); return dir($nodes, selector, nameIndex, 'previousElementSibling'); }; }); /** * next - 取得后一个匹配的元素 * @param selector {String=} * @return {JQ} */ /** * nextAll - 取得后面所有匹配的元素 * @param selector {String=} * @return {JQ} */ /** * nextUntil - 取得后面所有匹配的元素,直到遇到匹配的元素,不包含匹配的元素 * @param selector {String=} * @return {JQ} */ each(['', 'All', 'Until'], (nameIndex, name) => { $.fn['next' + name] = function(selector) { return dir(this, selector, nameIndex, 'nextElementSibling'); }; }); /** * parent - 取得匹配的直接父元素 * @param selector {String=} * @return {JQ} */ /** * parents - 取得所有匹配的父元素 * @param selector {String=} * @return {JQ} */ /** * parentUntil - 取得所有的父元素,直到遇到匹配的元素,不包含匹配的元素 * @param selector {String=} * @return {JQ} */ each(['', 's', 'sUntil'], (nameIndex, name) => { $.fn['parent' + name] = function(selector) { // parents、parentsUntil 需要把元素的顺序反向处理,以便和 jQuery 的结果一致 const $nodes = nameIndex === 0 ? this : $(this.get().reverse()); return dir($nodes, selector, nameIndex, 'parentNode'); }; }); /** * append - 在元素内部追加内容 * @param newChild {String|Node|NodeList|JQ} * @return {JQ} */ /** * prepend - 在元素内部前置内容 * @param newChild {String|Node|NodeList|JQ} * @return {JQ} */ each(['append', 'prepend'], (nameIndex, name) => { $.fn[name] = function(newChild) { let newChilds; const copyByClone = this.length > 1; if (isString(newChild) && (newChild[0] !== '<' || newChild[newChild.length - 1] !== '>')) { const tempDiv = document.createElement('div'); tempDiv.innerHTML = newChild; newChilds = [].slice.call(tempDiv.childNodes); } else { newChilds = $(newChild).get(); } if (nameIndex === 1) { // prepend newChilds.reverse(); } return this.each((i, _this) => { each(newChilds, (j, child) => { // 一个元素要同时追加到多个元素中,需要先复制一份,然后追加 if (copyByClone && i > 0) { child = child.cloneNode(true); } if (nameIndex === 0) { // append _this.appendChild(child); } else { // prepend _this.insertBefore(child, _this.childNodes[0]); } }); }); }; }); /** * insertBefore - 插入到指定元素的前面 * @param selector {String|Node|NodeList|JQ} * @return {JQ} */ /** * insertAfter - 插入到指定元素的后面 * @param selector {String|Node|NodeList|JQ} * @return {JQ} */ each(['insertBefore', 'insertAfter'], (nameIndex, name) => { $.fn[name] = function(selector) { const $elem = $(selector); return this.each((i, _this) => { $elem.each((j, elem) => { elem.parentNode.insertBefore( $elem.length === 1 ? _this : _this.cloneNode(true), nameIndex === 0 ? elem : elem.nextSibling ); }); }); }; }); /** * appendTo - 追加到指定元素内容 * @param selector {String|Node|NodeList|JQ} * @return {JQ} */ /** * prependTo - 前置到指定元素内部 * @param selector {String|Node|NodeList|JQ} * @return {JQ} */ /** * before - 插入到指定元素前面 * @param selector {String|Node|NodeList|JQ} * @return {JQ} */ /** * after - 插入到指定元素后面 * @param selector {String|Node|NodeList|JQ} * @return {JQ} */ /** * replaceAll - 替换掉指定元素 * @param selector {String|Node|NodeList|JQ} * @return {JQ} */ each({ appendTo: 'append', prependTo: 'prepend', before: 'insertBefore', after: 'insertAfter', replaceAll: 'replaceWith' }, (name, original) => { $.fn[name] = function(selector) { $(selector)[original](this); return this; }; }); const dataNS = 'mduiElementDataStorage'; $.extend({ /** * 在指定元素上存储数据,或从指定元素上读取数据 * @param elem 必须, DOM 元素 * @param key 必须,键名 * @param value 可选,值 */ data: function data(elem, key, value) { let data = {}; if (value !== undefined) { // 根据 key、value 设置值 data[key] = value; } else if (isObjectLike(key)) { // 根据键值对设置值 data = key; } else if (key === undefined) { // 获取所有值 const result = {}; each(elem.attributes, (i, attribute) => { const name = attribute.name; if (name.indexOf('data-') === 0) { const prop = name.slice(5).replace(/-./g, u => { return u.charAt(1).toUpperCase(); }); result[prop] = attribute.value; } }); if (elem[dataNS]) { each(elem[dataNS], (k, v) => { result[k] = v; }); } return result; } else if (elem[dataNS] && (key in elem[dataNS])) { // 获取指定值 return elem[dataNS][key]; } else { // 从 data- 中获取指定值 const dataKey = elem.getAttribute('data-' + key); if (dataKey) { return dataKey; } return undefined; } // 设置值 if (!elem[dataNS]) { elem[dataNS] = {}; } each(data, (k, v) => { elem[dataNS][k] = v; }); return undefined; }, /** * 移除指定元素上存放的数据 * @param elem 必须,DOM 元素 * @param key 必须,键名 */ removeData: function removeData(elem, key) { if (elem[dataNS] && elem[dataNS][key]) { elem[dataNS][key] = null; delete elem[dataNS][key]; } } }); $.fn.extend({ /** * 在元素上读取或设置数据 * @param key 必须 * @param value * @returns {*} */ data: function data(key, value) { if (value === undefined) { if (isObjectLike(key)) { // 同时设置多个值 return this.each((i, elem) => { $.data(elem, key); }); } if (this[0]) { // 获取值 return $.data(this[0], key); } return undefined; } // 设置值 return this.each((i, elem) => { $.data(elem, key, value); }); }, /** * 移除元素上存储的数据 * @param key 必须 * @returns {*} */ removeData: function removeData(key) { return this.each((i, elem) => { $.removeData(elem, key); }); } }); !(function() { try { return new e('test'); } catch (e) {} var e = function(e, t) { t = t || {bubbles: !1, cancelable: !1}; const n = document.createEvent('MouseEvent'); return n.initMouseEvent(e, t.bubbles, t.cancelable, window, 0, 0, 0, 0, 0, !1, !1, !1, !1, 0, null), n; }; e.prototype = Event.prototype, window.MouseEvent = e; }()); !(function() { function t(t, e) { e = e || {bubbles: !1, cancelable: !1, detail: void 0}; const n = document.createEvent('CustomEvent'); return n.initCustomEvent(t, e.bubbles, e.cancelable, e.detail), n; } typeof window.CustomEvent !== 'function' && (t.prototype = window.Event.prototype, window.CustomEvent = t); }()); // 存储事件 const handlers = { // i: { // 元素ID // j: { // 事件ID // e: 事件名 // fn: 事件处理函数 // i: 事件ID // proxy: // sel: 选择器 // } // } }; // 元素ID let mduiElementId = 1; function fnFalse() { return false; } /** * 为元素赋予一个唯一的ID * @param element * @returns {number|*} */ function getElementId(element) { if (!element.mduiElementId) { mduiElementId += 1; element.mduiElementId = mduiElementId; } return element.mduiElementId; } /** * 获取匹配的事件 * @param element * @param eventName * @param func * @param selector * @returns {Array} */ function getHandlers(element, eventName, func, selector) { return (handlers[getElementId(element)] || []).filter(handler => { return handler && (!eventName || handler.e === eventName) && (!func || handler.fn.toString() === func.toString()) && (!selector || handler.sel === selector); }); } /** * 添加事件监听 * @param element * @param eventName * @param func * @param data * @param selector */ function add(element, eventName, func, data, selector) { const elementId = getElementId(element); if (!handlers[elementId]) { handlers[elementId] = []; } // 传入 data.useCapture 来设置 useCapture: true let useCapture = false; if (isObjectLike(data) && data.useCapture) { useCapture = true; } eventName.split(' ').forEach(event => { const handler = { e: event, fn: func, sel: selector, i: handlers[elementId].length }; function callFn(e, elem) { // 因为鼠标事件模拟事件的 detail 属性是只读的,因此在 e._detail 中存储参数 /* eslint no-underscore-dangle: 0 */ const result = func.apply(elem, e._detail === undefined ? [e] : [e].concat(e._detail)); if (result === false) { e.preventDefault(); e.stopPropagation(); } } function proxyfn(e) { e._data = data; if (selector) { // 事件代理 $(element) .find(selector) .get() .reverse() .forEach(elem => { if (elem === e.target || $.contains(elem, e.target)) { callFn(e, elem); } }); } else { // 不使用事件代理 callFn(e, element); } } handler.proxy = proxyfn; handlers[elementId].push(handler); element.addEventListener(handler.e, proxyfn, useCapture); }); } /** * 移除事件监听 * @param element * @param eventName * @param func * @param selector */ function remove(element, eventName, func, selector) { (eventName || '').split(' ').forEach(event => { getHandlers(element, event, func, selector).forEach(handler => { delete handlers[getElementId(element)][handler.i]; element.removeEventListener(handler.e, handler.proxy, false); }); }); } $.fn.extend({ /** * DOM 加载完毕后调用的函数 * @param callback * @returns {ready} */ ready: function ready(callback) { if (/complete|loaded|interactive/.test(document.readyState) && document.body) { callback($); } else { document.addEventListener('DOMContentLoaded', () => { callback($); }, false); } return this; }, /** * 绑定事件 * * $().on({eventName: fn}, selector, data); * $().on({eventName: fn}, selector) * $().on({eventName: fn}) * $().on(eventName, selector, data, fn); * $().on(eventName, selector, fn); * $().on(eventName, data, fn); * $().on(eventName, fn); * $().on(eventName, false); * * @param eventName * @param selector * @param data * @param callback * @param one 是否是 one 方法,只在 JQ 内部使用 * @returns */ on: function on(eventName, selector, data, callback, one) { const self = this; // 默认 // $().on(event, selector, data, callback) // event 使用 事件:函数 键值对 // event = { // 'event1': callback1, // 'event2': callback2 // } // // $().on(event, selector, data) if (eventName && !isString(eventName)) { each(eventName, (type, fn) => { self.on(type, selector, data, fn); }); return self; } // selector 不存在 // $().on(event, data, callback) if (!isString(selector) && !isFunction(callback) && callback !== false) { callback = data; data = selector; selector = undefined; } // data 不存在 // $().on(event, callback) if (isFunction(data) || data === false) { callback = data; data = undefined; } // callback 为 false // $().on(event, false) if (callback === false) { callback = fnFalse; } if (one === 1) { const origCallback = callback; callback = function() { self.off(eventName, selector, callback); /* eslint prefer-rest-params: 0 */ return origCallback.apply(this, arguments); }; } return this.each(function() { add(this, eventName, callback, data, selector); }); }, /** * 绑定事件,只触发一次 * @param eventName * @param selector * @param data * @param callback */ one: function one(eventName, selector, data, callback) { const self = this; if (!isString(eventName)) { each(eventName, (type, fn) => { type.split(' ').forEach(eName => { self.on(eName, selector, data, fn, 1); }); }); } else { eventName.split(' ').forEach(eName => {