|
|
/*!
@Title: layui @Description:经典模块化前端 UI 框架 @Site: www.layui.com @Author: 贤心 @License:MIT
*/
!(function (win) { 'use strict';
var doc = document; var config = { modules: {}, // 记录模块物理路径 status: {}, // 记录模块加载状态 timeout: 10, // 符合规范的模块请求最长等待秒数 event: {}, // 记录模块自定义事件 version: '30233', // 系统版本号 为了解决浏览器的缓存问题; 系统中的js、html文件路径都会拼上此版本号 }; var Layui = function () { this.v = '2.5.5'; // 版本号 }; // 获取layui所在目录 var getPath = (function () { var jsPath = doc.currentScript ? doc.currentScript.src : (function () { var js = doc.scripts; var last = js.length - 1; var src; for (var i = last; i > 0; i--) { if (js[i].readyState === 'interactive') { src = js[i].src; break; } } return src || js[last].src; })(); return jsPath.substring(0, jsPath.lastIndexOf('/') + 1); })(); // 异常提示 var error = function (msg) { win.console && console.error && console.error('Layui hint: ' + msg); }; var isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]'; // 内置模块 var modules = { layer: 'modules/layer', // 弹层 laydate: 'modules/laydate', // 日期 laypage: 'modules/laypage', // 分页 laytpl: 'modules/laytpl', // 模板引擎 layim: 'modules/layim', // web通讯 layedit: 'modules/layedit', // 富文本编辑器 form: 'modules/form', // 表单集 upload: 'modules/upload', // 上传 transfer: 'modules/transfer', // 上传 tree: 'modules/tree', // 树结构 table: 'modules/table', // 表格 element: 'modules/element', // 常用元素操作 rate: 'modules/rate', // 评分组件 colorpicker: 'modules/colorpicker', // 颜色选择器 slider: 'modules/slider', // 滑块 carousel: 'modules/carousel', // 轮播 flow: 'modules/flow', // 流加载 util: 'modules/util', // 工具块 code: 'modules/code', // 代码修饰器 jquery: 'modules/jquery', // DOM库(第三方) mobile: 'modules/mobile', // 移动大模块 | 若当前为开发目录,则为移动模块入口,否则为移动模块集合 'layui.all': '../layui.all', // PC模块合并版 };
// 记录基础数据 Layui.prototype.cache = config;
// 定义模块 Layui.prototype.define = function (deps, factory) { var that = this; var type = typeof deps === 'function'; var callback = function () { var setApp = function (app, exports) { layui[app] = exports; config.status[app] = true; }; typeof factory === 'function' && factory(function (app, exports) { setApp(app, exports); config.callback[app] = function () { factory(setApp); }; }); return this; };
type && ((factory = deps), (deps = []));
if (!layui['layui.all'] && layui['layui.mobile']) { return callback.call(that); }
that.use(deps, callback); return that; };
// 使用特定模块 Layui.prototype.use = function (apps, callback, exports) { var that = this; var dir = (config.dir = config.dir ? config.dir : getPath); var head = doc.getElementsByTagName('head')[0];
apps = typeof apps === 'string' ? [apps] : apps;
// 如果页面已经存在jQuery1.7+库且所定义的模块依赖jQuery,则不加载内部jquery模块 if (window.jQuery && jQuery.fn.on) { that.each(apps, function (index, item) { if (item === 'jquery') { apps.splice(index, 1); } }); layui.jquery = layui.$ = jQuery; }
var item = apps[0]; var timeout = 0; exports = exports || [];
// 静态资源host config.host = config.host || (dir.match(/\/\/([\s\S]+?)\//) || ['//' + location.host + '/'])[0];
// 加载完毕 function onScriptLoad (e, url) { var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/; if (e.type === 'load' || readyRegExp.test((e.currentTarget || e.srcElement).readyState)) { config.modules[item] = url; head.removeChild(node); (function poll () { if (++timeout > (config.timeout * 1000) / 4) { return error(item + ' is not a valid module'); } config.status[item] ? onCallback() : setTimeout(poll, 4); })(); } }
// 回调 function onCallback () { exports.push(layui[item]); apps.length > 1 ? that.use(apps.slice(1), callback, exports) : typeof callback === 'function' && callback.apply(layui, exports); }
// 如果引入了完整库(layui.all.js),内置的模块则不必再加载 if ( apps.length === 0 || (layui['layui.all'] && modules[item]) || (!layui['layui.all'] && layui['layui.mobile'] && modules[item]) ) { return onCallback(), that; }
// 首次加载模块 if (!config.modules[item]) { var node = doc.createElement('script'); // 如果是内置模块,则按照 dir 参数拼接模块路径 // 如果是扩展模块,则判断模块路径值是否为 {/} 开头, // 如果路径值是 {/} 开头,则模块路径即为后面紧跟的字符。 // 否则,则按照 base 参数拼接模块路径 var url = (modules[item] ? dir + 'lay/' : /^\{\/\}/.test(that.modules[item]) ? '' : config.base || '') + (that.modules[item] || item) + '.js';
url = url.replace(/^\{\/\}/, '');
node.async = true; node.charset = 'utf-8'; node.src = url + (function () { var version = config.version === true ? config.v || new Date().getTime() : config.version || ''; return version ? '?v=' + version : ''; })();
head.appendChild(node);
if ( node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera ) { node.attachEvent('onreadystatechange', function (e) { onScriptLoad(e, url); }); } else { node.addEventListener( 'load', function (e) { onScriptLoad(e, url); }, false ); }
config.modules[item] = url; } else { // 缓存 (function poll () { if (++timeout > (config.timeout * 1000) / 4) { return error(item + ' is not a valid module'); } typeof config.modules[item] === 'string' && config.status[item] ? onCallback() : setTimeout(poll, 4); })(); }
return that; };
// 获取节点的style属性值 Layui.prototype.getStyle = function (node, name) { var style = node.currentStyle ? node.currentStyle : win.getComputedStyle(node, null); return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name); };
// css外部加载器 Layui.prototype.link = function (href, fn, cssname) { var that = this; var link = doc.createElement('link'); var head = doc.getElementsByTagName('head')[0];
if (typeof fn === 'string') { cssname = fn; }
var app = (cssname || href).replace(/\.|\//g, ''); var id = (link.id = 'layuicss-' + app); var timeout = 0;
link.rel = 'stylesheet'; link.href = href + (config.debug ? '?v=' + new Date().getTime() : ''); link.media = 'all';
if (!doc.getElementById(id)) { head.appendChild(link); }
if (typeof fn !== 'function') { return that; }
// 轮询css是否加载完毕 (function poll () { if (++timeout > (config.timeout * 1000) / 100) { return error(href + ' timeout'); } parseInt(that.getStyle(doc.getElementById(id), 'width')) === 1989 ? (function () { fn(); })() : setTimeout(poll, 100); })();
return that; };
// 存储模块的回调 config.callback = {};
// 重新执行模块的工厂函数 Layui.prototype.factory = function (modName) { if (layui[modName]) { return typeof config.callback[modName] === 'function' ? config.callback[modName] : null; } };
// css内部加载器 Layui.prototype.addcss = function (firename, fn, cssname) { return layui.link(config.dir + 'css/' + firename, fn, cssname); };
// 图片预加载 Layui.prototype.img = function (url, callback, error) { var img = new Image(); img.src = url; if (img.complete) { return callback(img); } img.onload = function () { img.onload = null; typeof callback === 'function' && callback(img); }; img.onerror = function (e) { img.onerror = null; typeof error === 'function' && error(e); }; };
// 全局配置 Layui.prototype.config = function (options) { options = options || {}; for (var key in options) { config[key] = options[key]; } return this; };
// 记录全部模块 Layui.prototype.modules = (function () { var clone = {}; for (var o in modules) { clone[o] = modules[o]; } return clone; })();
// 拓展模块 Layui.prototype.extend = function (options) { var that = this;
// 验证模块是否被占用 options = options || {}; for (var o in options) { if (that[o] || that.modules[o]) { error('\u6A21\u5757\u540D ' + o + ' \u5DF2\u88AB\u5360\u7528'); } else { that.modules[o] = options[o]; } }
return that; };
// 路由解析 Layui.prototype.router = function (hash) { var that = this; var hash = hash || location.hash; var data = { path: [], search: {}, hash: (hash.match(/[^#](#.*$)/) || [])[1] || '', };
if (!/^#\//.test(hash)) { return data; } // 禁止非路由规范 hash = hash.replace(/^#\//, ''); data.href = '/' + hash; hash = hash.replace(/([^#])(#.*$)/, '$1').split('/') || [];
// 提取Hash结构 that.each(hash, function (index, item) { /^\w+=/.test(item) ? (function () { item = item.split('='); data.search[item[0]] = item[1]; })() : data.path.push(item); });
return data; };
// 本地持久性存储 Layui.prototype.data = function (table, settings, storage) { table = table || 'layui'; storage = storage || localStorage;
if (!win.JSON || !win.JSON.parse) { return; }
// 如果settings为null,则删除表 if (settings === null) { return delete storage[table]; }
settings = typeof settings === 'object' ? settings : { key: settings };
try { var data = JSON.parse(storage[table]); } catch (e) { var data = {}; }
if ('value' in settings) { data[settings.key] = settings.value; } if (settings.remove) { delete data[settings.key]; } storage[table] = JSON.stringify(data);
return settings.key ? data[settings.key] : data; };
// 本地会话性存储 Layui.prototype.sessionData = function (table, settings) { return this.data(table, settings, sessionStorage); };
// 设备信息 Layui.prototype.device = function (key) { var agent = navigator.userAgent.toLowerCase(); // 获取版本号 var getVersion = function (label) { var exp = new RegExp(label + '/([^\\s\\_\\-]+)'); label = (agent.match(exp) || [])[1]; return label || false; }; // 返回结果集 var result = { os: (function () { // 底层操作系统 if (/windows/.test(agent)) { return 'windows'; } else if (/linux/.test(agent)) { return 'linux'; } else if (/iphone|ipod|ipad|ios/.test(agent)) { return 'ios'; } else if (/mac/.test(agent)) { return 'mac'; } })(), ie: (function () { // ie版本 return !!win.ActiveXObject || 'ActiveXObject' in win ? (agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于ie11并没有msie的标识 : false; })(), weixin: getVersion('micromessenger'), // 是否微信 };
// 任意的key if (key && !result[key]) { result[key] = getVersion(key); }
// 移动设备 result.android = /android/.test(agent); result.ios = result.os === 'ios';
return result; };
// 提示 Layui.prototype.hint = function () { return { error: error, }; };
// 遍历 Layui.prototype.each = function (obj, fn) { var key; var that = this; if (typeof fn !== 'function') { return that; } obj = obj || []; if (obj.constructor === Object) { for (key in obj) { if (fn.call(obj[key], key, obj[key])) { break; } } } else { for (key = 0; key < obj.length; key++) { if (fn.call(obj[key], key, obj[key])) { break; } } } return that; };
// 将数组中的对象按其某个成员排序 Layui.prototype.sort = function (obj, key, desc) { var clone = JSON.parse(JSON.stringify(obj || []));
if (!key) { return clone; }
// 如果是数字,按大小排序,如果是非数字,按字典序排序 clone.sort(function (o1, o2) { var isNum = /^-?\d+$/; var v1 = o1[key]; var v2 = o2[key];
if (isNum.test(v1)) { v1 = parseFloat(v1); } if (isNum.test(v2)) { v2 = parseFloat(v2); }
if (v1 && !v2) { return 1; } else if (!v1 && v2) { return -1; }
if (v1 > v2) { return 1; } else if (v1 < v2) { return -1; } else { return 0; } });
desc && clone.reverse(); // 倒序 return clone; };
// 阻止事件冒泡 Layui.prototype.stope = function (thisEvent) { thisEvent = thisEvent || win.event; try { thisEvent.stopPropagation(); } catch (e) { thisEvent.cancelBubble = true; } };
// 自定义模块事件 Layui.prototype.onevent = function (modName, events, callback) { if (typeof modName !== 'string' || typeof callback !== 'function') { return this; }
return Layui.event(modName, events, null, callback); };
// 执行自定义模块事件 Layui.prototype.event = Layui.event = function (modName, events, params, fn) { var that = this; var result = null; var filter = events.match(/\((.*)\)$/) || []; // 提取事件过滤器字符结构,如:select(xxx) var eventName = (modName + '.' + events).replace(filter[0], ''); // 获取事件名称,如:form.select var filterName = filter[1] || ''; // 获取过滤器名称,,如:xxx var callback = function (_, item) { var res = item && item.call(that, params); res === false && result === null && (result = false); };
// 添加事件 if (fn) { config.event[eventName] = config.event[eventName] || {};
// 这里不再对多次事件监听做支持,避免更多麻烦 // config.event[eventName][filterName] ? config.event[eventName][filterName].push(fn) : config.event[eventName][filterName] = [fn]; return this; }
// 执行事件回调 layui.each(config.event[eventName], function (key, item) { // 执行当前模块的全部事件 if (filterName === '{*}') { layui.each(item, callback); return; }
// 执行指定事件 key === '' && layui.each(item, callback); filterName && key === filterName && layui.each(item, callback); }); return result; };
// 加载自定义事件 NodeList.prototype.forEach = Array.prototype.forEach; window.customEvent = { rootScope: { name: 'document', handleEvent: {}, events: {}, children: [], },
/** * @description: 用于处理模板解析 * @param {String} template 传递已经被latpl编译的模板 * @param {String} locationId id * @return {String} 返回已经被latpl编译的模板 */ parse: function (template, locationId) { var $ = layui.$; // 查找父级组件 var that = this; var currentScope = null; if (!locationId) { // 根节点初始化Scope currentScope = that.rootScope; } else { var parentId = $("*[edoc='" + locationId + "']") .parents('*[edoc]') .first() .attr('edoc'); var parentScope = that.findScope(parentId, that.rootScope) || that.rootScope; var currentScope = that.findScope(locationId, that.rootScope); if (!currentScope) { currentScope = { name: locationId, handleEvent: {}, events: {}, }; parentScope.children ? parentScope.children.push(currentScope) : (parentScope.children = [currentScope]); } } // 匹配模板内部存在 @ 绑定事件的DOM return template.replace(/<[^<]*(@\w*=\w*(\(\S*\))?\s*)+[^>]*>/gi, function (domStr) { var randomFlag = 'data-ident=' + Math.floor(Math.random() * 1000); while (currentScope.handleEvent[randomFlag]) { randomFlag = 'data-ident=' + Math.floor(Math.random() * 1000); } // 初始化handleEvent currentScope.handleEvent[randomFlag] = {}; // 替换生成唯一标记 然后匹配DOM上的绑定事件 // (\((?<=\()[^\)]+\))? return domStr .replace('>', ' ' + randomFlag + ' >') .replace(/@\w*=\w*(\([^\)]+\))?\s*/gi, function (subStr) { // 生成绑定事件的格式 var event = subStr.replace('@', '').trim().split('='); currentScope.handleEvent[randomFlag][event[0]] = event[1]; return ''; }); }); },
/** * @description: 用于绑定监听事件,并触发相关的回调 * @param {Object} data data * @param {String} locationId id * @return {Object} null */ bindEvent: function (data, locationId) { var $ = layui.$; var currentScope = this.findScope(locationId, this.rootScope) || this.rootScope; var filter = $(locationId ? '*[edoc="' + currentScope.name + '"]' : 'body'); try { Object.keys(currentScope.handleEvent).forEach(function (event) { if (currentScope.handleEvent[event].bindStatus) {return null;} var _EventDOM = filter.find('*[' + event + ']'); var _Events = currentScope.handleEvent[event.trim()]; Object.keys(_Events).forEach(function (_EventName) { var _FnTemp = _Events[_EventName].split('('); var _FnName = _FnTemp[0]; var _FnArgs = _FnTemp[1] ? _FnTemp[1].replace(')', '') : data; try { if (typeof _FnArgs === 'string' && isNaN(_FnArgs)) { _FnArgs = JSON.parse(_FnArgs); } } catch (e) { console.error(_FnArgs, '参数无法转化为对象', e); } _EventDOM.on(_EventName, function (event) { currentScope.events[_FnName](_FnArgs, event.currentTarget); }); Object.defineProperty(currentScope.handleEvent[event], 'bindStatus', { value: true, }); }); }); } catch (error) { console.error(error); } },
/** * @description: 用于提供回调以挂载给绑定事件调用 * @param {String} name 回调函数名称 * @param {Function} callback 回调函数 * @return {Object} null */ toggleEvent: function (name, callback) { var customEvent = window.customEvent; var currentScope = this.constructor.name === 'Object' ? customEvent.rootScope : customEvent.findScope(this.id, customEvent.rootScope); if (currentScope && currentScope.events) {currentScope.events[name] = callback;} }, // refresh:function(locationId){ var that=this try { var node=that.findScope(locationId,that.rootScope) if(node){ node.handleEvent={}, node.events={} } } catch (error) { console.log(error); } }, // 依赖方法 /** * @description:数组去重 * @param {Array} arr 重复数组 * @return {Array} 去重数组 */ unique: function (arr) { var obj = {}; var newArr = []; for (var i = 0; i < arr.length; i++) { if (obj[arr[i]] === undefined) { newArr.push(arr[i]); obj[arr[i]] = 1; } } return newArr; }, /** * @description: 查找作用域(不查根节点) * @param {String} scopeName 作用域名词 * @param {Object} scopeTree 作用域树 * @return {Object} scope */ findScope: function (scopeName, scopeTree) { try { var childScopes = scopeTree.children; for (var index = 0; index < childScopes.length; index++) { var scope = childScopes[index]; if (scope.name === scopeName) { return scope; } if (scope.children) { var result = window.customEvent.findScope(scopeName, scope); if (result) { return result; } } } return null; } catch (error) { console.log(error); } }, };
win.layui = new Layui(); })(window);
|