2022-05-18 22:35:13 +08:00
|
|
|
|
/**
|
2021-05-18 02:42:31 +08:00
|
|
|
|
* Layui
|
2022-05-24 18:19:06 +08:00
|
|
|
|
* Classic modular front-end UI library
|
2021-05-08 06:31:19 +08:00
|
|
|
|
* MIT Licensed
|
2017-08-21 08:51:13 +08:00
|
|
|
|
*/
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
(function(window) {
|
|
|
|
|
'use strict';
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 便于打包时的字符压缩
|
|
|
|
|
var document = window.document;
|
|
|
|
|
var location = window.location;
|
|
|
|
|
|
|
|
|
|
// 基础配置
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var config = {
|
|
|
|
|
timeout: 10, // 符合规范的模块请求最长等待秒数
|
2025-03-14 18:42:30 +08:00
|
|
|
|
debug: false, // 是否开启调试模式
|
|
|
|
|
version: false // 是否在模块请求时加入版本号参数(以更新模块缓存)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 模块加载缓存信息
|
|
|
|
|
var cache = {
|
|
|
|
|
modules: {}, // 模块物理路径
|
|
|
|
|
status: {}, // 模块加载就绪状态
|
|
|
|
|
event: {}, // 模块自定义事件
|
|
|
|
|
callback: {} // 模块的回调
|
2023-05-04 10:17:04 +08:00
|
|
|
|
};
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// constructor
|
|
|
|
|
var Class = function() {
|
2025-04-15 14:59:09 +08:00
|
|
|
|
this.v = '2.11.0-rc.3'; // 版本号
|
2023-05-04 10:17:04 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 识别预先可能定义的指定全局对象
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var GLOBAL = window.LAYUI_GLOBAL || {};
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 获取 layui 所在目录
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var getPath = function() {
|
|
|
|
|
var jsPath = (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') ? document.currentScript.src : function(){
|
|
|
|
|
var js = document.getElementsByTagName('script');
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var last = js.length - 1;
|
|
|
|
|
var src;
|
2017-11-16 07:34:22 +08:00
|
|
|
|
for(var i = last; i > 0; i--){
|
|
|
|
|
if(js[i].readyState === 'interactive'){
|
|
|
|
|
src = js[i].src;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return src || js[last].src;
|
|
|
|
|
}();
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2021-05-08 06:31:19 +08:00
|
|
|
|
return config.dir = GLOBAL.dir || jsPath.substring(0, jsPath.lastIndexOf('/') + 1);
|
2023-05-04 10:17:04 +08:00
|
|
|
|
}();
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 异常提示
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var error = function(msg, type) {
|
2021-03-31 14:07:23 +08:00
|
|
|
|
type = type || 'log';
|
2025-03-14 18:42:30 +08:00
|
|
|
|
window.console && console[type] && console[type]('layui error hint: ' + msg);
|
2023-05-04 10:17:04 +08:00
|
|
|
|
};
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 内置模块
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var builtinModules = config.builtin = {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
lay: 'lay', // 基础 DOM 操作
|
|
|
|
|
layer: 'layer', // 弹层
|
|
|
|
|
laydate: 'laydate', // 日期
|
|
|
|
|
laypage: 'laypage', // 分页
|
|
|
|
|
laytpl: 'laytpl', // 模板引擎
|
|
|
|
|
form: 'form', // 表单集
|
|
|
|
|
upload: 'upload', // 上传
|
|
|
|
|
dropdown: 'dropdown', // 下拉菜单
|
|
|
|
|
transfer: 'transfer', // 穿梭框
|
|
|
|
|
tree: 'tree', // 树结构
|
|
|
|
|
table: 'table', // 表格
|
|
|
|
|
treeTable: 'treeTable', // 树表
|
2025-01-20 10:25:36 +08:00
|
|
|
|
tabs: 'tabs', // 标签页
|
2023-05-04 10:17:04 +08:00
|
|
|
|
element: 'element', // 常用元素操作
|
|
|
|
|
rate: 'rate', // 评分组件
|
|
|
|
|
colorpicker: 'colorpicker', // 颜色选择器
|
|
|
|
|
slider: 'slider', // 滑块
|
|
|
|
|
carousel: 'carousel', // 轮播
|
|
|
|
|
flow: 'flow', // 流加载
|
|
|
|
|
util: 'util', // 工具块
|
|
|
|
|
code: 'code', // 代码修饰器
|
|
|
|
|
jquery: 'jquery', // DOM 库(第三方)
|
2025-01-20 10:25:36 +08:00
|
|
|
|
component: 'component', // 组件构建器
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-05-04 10:17:04 +08:00
|
|
|
|
all: 'all',
|
|
|
|
|
'layui.all': 'layui.all' // 聚合标识(功能性的,非真实模块)
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 低版本浏览器适配
|
|
|
|
|
* @see polyfill
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Object.assign
|
|
|
|
|
if (typeof Object.assign !== 'function') {
|
|
|
|
|
Object.assign = function(target) {
|
|
|
|
|
var to = Object(target);
|
|
|
|
|
if (arguments.length < 2) return to;
|
|
|
|
|
|
|
|
|
|
var sourcesIndex = 1;
|
|
|
|
|
for (; sourcesIndex < arguments.length; sourcesIndex++) {
|
|
|
|
|
var nextSource = arguments[sourcesIndex];
|
|
|
|
|
if (!(nextSource === undefined || nextSource === null)) {
|
|
|
|
|
for (var nextKey in nextSource) {
|
|
|
|
|
// 确保属性是源对象自身的(而非来自继承)
|
|
|
|
|
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
|
|
|
|
to[nextKey] = nextSource[nextKey];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return to;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 节点加载事件
|
|
|
|
|
* @param {HTMLElement} node - script 或 link 节点
|
|
|
|
|
* @param {Function} done
|
|
|
|
|
* @param {Function} error
|
|
|
|
|
*/
|
|
|
|
|
var onNodeLoad = function(node, done, error) {
|
|
|
|
|
// 资源加载完毕
|
|
|
|
|
var onCompleted = function (e) {
|
|
|
|
|
var readyRegExp = /^(complete|loaded)$/;
|
|
|
|
|
if (e.type === 'load' || (readyRegExp.test((e.currentTarget || e.srcElement).readyState))) {
|
|
|
|
|
removeListener();
|
|
|
|
|
typeof done === 'function' && done(e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// 资源加载失败
|
|
|
|
|
var onError = function (e) {
|
|
|
|
|
removeListener();
|
|
|
|
|
typeof error === 'function' && error(e);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 移除事件
|
|
|
|
|
var removeListener = function() {
|
|
|
|
|
if (node.detachEvent) {
|
|
|
|
|
node.detachEvent('onreadystatechange', onCompleted);
|
|
|
|
|
} else {
|
|
|
|
|
node.removeEventListener('load', onCompleted, false);
|
|
|
|
|
node.removeEventListener('error', onError, false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 添加事件
|
|
|
|
|
if(node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0)){
|
|
|
|
|
// 此处考虑到 IE9+ load 的稳定性,固仍然采用 onreadystatechange
|
|
|
|
|
node.attachEvent('onreadystatechange', onCompleted);
|
|
|
|
|
} else {
|
|
|
|
|
node.addEventListener('load', onCompleted, false);
|
|
|
|
|
node.addEventListener('error', onError, false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 或许配置及临时缓存信息
|
|
|
|
|
Class.prototype.cache = Object.assign(config, cache);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 全局配置
|
|
|
|
|
* @param {Object} options
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.config = function(options) {
|
|
|
|
|
Object.assign(config, options);
|
|
|
|
|
return this;
|
|
|
|
|
};
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 定义模块
|
|
|
|
|
* @param {(string|string[])} deps - 依赖的模块列表
|
|
|
|
|
* @param {Function} callback - 模块的回调
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.define = function(deps, callback) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var useCallback = function() {
|
|
|
|
|
var setModule = function(mod, exports) {
|
|
|
|
|
layui[mod] = exports; // 将模块接口赋值在 layui 对象中
|
|
|
|
|
cache.status[mod] = true; // 标记模块注册完成
|
2018-01-03 09:55:45 +08:00
|
|
|
|
};
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 执行模块的回调
|
|
|
|
|
typeof callback === 'function' && callback(function(mod, exports) {
|
|
|
|
|
setModule(mod, exports);
|
|
|
|
|
// 记录模块回调,以便需要时再执行
|
|
|
|
|
cache.callback[mod] = function() {
|
|
|
|
|
callback(setModule);
|
2018-01-03 09:55:45 +08:00
|
|
|
|
}
|
2017-08-21 08:51:13 +08:00
|
|
|
|
});
|
|
|
|
|
return this;
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 若未依赖模块
|
|
|
|
|
if (typeof deps === 'function') {
|
|
|
|
|
callback = deps;
|
|
|
|
|
deps = [];
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
that.use(deps, useCallback, null, 'define');
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return that;
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 使用模块
|
|
|
|
|
* @param {(string|string[])} mods - 模块列表
|
|
|
|
|
* @param {Function} callback - 回调
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.use = function(mods, callback, exports, from) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
|
|
|
|
var dir = config.dir = config.dir ? config.dir : getPath;
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 整理模块队列
|
|
|
|
|
mods = (function() {
|
|
|
|
|
if (typeof mods === 'string') {
|
|
|
|
|
return [mods];
|
2023-11-14 22:14:19 +08:00
|
|
|
|
}
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 若第一个参数为 function ,则自动加载所有内置模块,且执行的回调即为该 function 参数;
|
|
|
|
|
else if(typeof mods === 'function') {
|
|
|
|
|
callback = mods;
|
2021-04-05 23:41:30 +08:00
|
|
|
|
return ['all'];
|
2023-11-14 22:14:19 +08:00
|
|
|
|
}
|
2025-03-14 18:42:30 +08:00
|
|
|
|
return mods;
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
// 获取 layui 静态资源所在 host
|
|
|
|
|
if (!config.host) {
|
|
|
|
|
config.host = (dir.match(/\/\/([\s\S]+?)\//)||['//'+ location.host +'/'])[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 若参数异常
|
|
|
|
|
if (!mods) return that;
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 若页面已经存在 jQuery 且所定义的模块依赖 jQuery,则不加载内部 jquery 模块
|
|
|
|
|
if (window.jQuery && jQuery.fn.on) {
|
|
|
|
|
that.each(mods, function(index, item) {
|
|
|
|
|
if (item === 'jquery') {
|
|
|
|
|
mods.splice(index, 1);
|
2017-08-21 08:51:13 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
2025-03-14 18:42:30 +08:00
|
|
|
|
layui.jquery = layui.$ = window.jQuery;
|
2017-08-21 08:51:13 +08:00
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 将模块的接口作为回调的参数传递
|
2017-08-21 08:51:13 +08:00
|
|
|
|
exports = exports || [];
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 加载当前队列的第一个模块
|
|
|
|
|
var item = mods[0];
|
|
|
|
|
var modInfo = that.modules[item]; // 当前模块信息
|
|
|
|
|
// 是否为外部模块,即无需遵循 layui 轻量级模块规范的任意第三方组件。
|
|
|
|
|
var isExternalModule = typeof modInfo === 'object';
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 回调触发
|
|
|
|
|
var onCallback = function () {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
exports.push(layui[item]);
|
2025-03-14 18:42:30 +08:00
|
|
|
|
mods.length > 1
|
|
|
|
|
? that.use(mods.slice(1), callback, exports, from)
|
|
|
|
|
: (typeof callback === 'function' && function() {
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 保证文档加载完毕再执行回调
|
2021-04-06 16:01:23 +08:00
|
|
|
|
if(layui.jquery && typeof layui.jquery === 'function' && from !== 'define'){
|
2021-04-05 23:41:30 +08:00
|
|
|
|
return layui.jquery(function(){
|
|
|
|
|
callback.apply(layui, exports);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
callback.apply(layui, exports);
|
|
|
|
|
}() );
|
2025-03-14 18:42:30 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 回调轮询
|
|
|
|
|
var pollCallback = function () {
|
|
|
|
|
var timeout = 0; // 超时计数器(秒)
|
|
|
|
|
var delay = 5; // 轮询等待毫秒数
|
|
|
|
|
|
|
|
|
|
// 轮询模块加载完毕状态
|
|
|
|
|
(function poll() {
|
|
|
|
|
if (++timeout > config.timeout * 1000 / delay) {
|
|
|
|
|
return error(item + ' is not a valid module', 'error');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 根据模块加载完毕的标志来完成轮询
|
|
|
|
|
// 若为任意外部模块,则标志为该模块接口是否存在;
|
|
|
|
|
// 若为遵循 layui 规范的模块,则标志为模块的 status 状态值
|
|
|
|
|
(isExternalModule ? layui[item] = window[modInfo.api] : cache.status[item])
|
|
|
|
|
? onCallback()
|
|
|
|
|
: setTimeout(poll, delay);
|
|
|
|
|
})();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 若为发行版,则内置模块不必异步加载
|
|
|
|
|
if (mods.length === 0 || (layui['layui.all'] && builtinModules[item])) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return onCallback(), that;
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 当前模块所在路径
|
|
|
|
|
var modSrc = isExternalModule ? modInfo.src : modInfo;
|
|
|
|
|
|
|
|
|
|
// 基础路径
|
|
|
|
|
var basePath = builtinModules[item]
|
|
|
|
|
? (dir + 'modules/') // 若为内置模块,则按照默认 dir 参数拼接模块 URL
|
|
|
|
|
: (modSrc ? '' : config.base); // 若为扩展模块,且模块路径已设置,则不必再重复拼接基础路径
|
|
|
|
|
|
|
|
|
|
// 若从 layui.modules 为获取到模块路径, 则将传入的模块名视为路径名
|
|
|
|
|
if (!modSrc) modSrc = item;
|
|
|
|
|
|
|
|
|
|
// 过滤空格符和 .js 后缀
|
|
|
|
|
modSrc = modSrc.replace(/\s/g, '').replace(/\.js[^\/\.]*$/, '');
|
|
|
|
|
|
|
|
|
|
// 拼接最终模块 URL
|
|
|
|
|
var url = basePath + modSrc + '.js';
|
|
|
|
|
|
|
|
|
|
// 若扩展模块对象已经存在,则不必再重复加载
|
|
|
|
|
if(!cache.modules[item] && layui[item]){
|
|
|
|
|
cache.modules[item] = url; // 并记录起该扩展模块的 url
|
2020-01-15 06:30:00 +08:00
|
|
|
|
}
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 首次加载模块
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (!cache.modules[item]) {
|
|
|
|
|
var head = document.getElementsByTagName('head')[0];
|
|
|
|
|
var node = document.createElement('script');
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
node.async = true;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
node.charset = 'utf-8'; // 避免 IE9 的编码问题
|
|
|
|
|
node.src = url + function() {
|
2023-11-14 22:14:19 +08:00
|
|
|
|
var version = config.version === true
|
2025-03-14 18:42:30 +08:00
|
|
|
|
? (config.v || (new Date()).getTime())
|
|
|
|
|
: (config.version || '');
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return version ? ('?v=' + version) : '';
|
|
|
|
|
}();
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
head.appendChild(node);
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 节点加载事件
|
|
|
|
|
onNodeLoad(node, function() {
|
|
|
|
|
head.removeChild(node);
|
|
|
|
|
pollCallback();
|
|
|
|
|
}, function() {
|
|
|
|
|
head.removeChild(node);
|
|
|
|
|
});
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 模块已首次加载的标记
|
|
|
|
|
cache.modules[item] = url;
|
|
|
|
|
} else { // 再次 use 模块
|
|
|
|
|
pollCallback();
|
2017-08-21 08:51:13 +08:00
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return that;
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 记录全部模块
|
|
|
|
|
Class.prototype.modules = Object.assign({}, builtinModules);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 拓展模块
|
|
|
|
|
* @param {Object} settings - 拓展模块的配置
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.extend = function(settings) {
|
2022-06-19 02:10:15 +08:00
|
|
|
|
var that = this;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var base = config.base || '';
|
|
|
|
|
var firstSymbolEXP = /^\{\/\}/; // 模块单独路径首字符表达式
|
|
|
|
|
|
|
|
|
|
settings = settings || {};
|
|
|
|
|
|
|
|
|
|
// 遍历拓展模块
|
|
|
|
|
for (var modName in settings) {
|
|
|
|
|
if (that[modName] || that.modules[modName]) { // 验证模块是否被占用
|
|
|
|
|
error('the '+ modName + ' module already exists, extend failure');
|
|
|
|
|
} else {
|
|
|
|
|
var modInfo = settings[modName];
|
|
|
|
|
// 若直接传入模块路径字符
|
|
|
|
|
if (typeof modInfo === 'string') {
|
|
|
|
|
// 判断传入的模块路径是否特定首字符
|
|
|
|
|
// 若存在特定首字符,则模块 URL 即为该首字符后面紧跟的字符
|
|
|
|
|
// 否则,则按照 config.base 路径进行拼接
|
|
|
|
|
if (firstSymbolEXP.test(modInfo)) base = '';
|
|
|
|
|
modInfo = (base + modInfo).replace(firstSymbolEXP, '');
|
|
|
|
|
}
|
|
|
|
|
that.modules[modName] = modInfo;
|
2022-06-19 02:10:15 +08:00
|
|
|
|
}
|
2025-03-14 18:42:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return that;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 弃用指定的模块,以便重新扩展新的同名模块。
|
|
|
|
|
* @param {(string|string[])} mods - 模块列表
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.disuse = function(mods) {
|
|
|
|
|
var that = this;
|
|
|
|
|
mods = that.isArray(mods) ? mods : [mods];
|
|
|
|
|
that.each(mods, function (index, item) {
|
2022-06-19 02:10:15 +08:00
|
|
|
|
delete that[item];
|
2025-03-14 18:42:30 +08:00
|
|
|
|
delete builtinModules[item];
|
2022-06-19 02:10:15 +08:00
|
|
|
|
delete that.modules[item];
|
2025-03-14 18:42:30 +08:00
|
|
|
|
delete cache.status[item];
|
|
|
|
|
delete cache.modules[item];
|
2022-06-21 00:25:07 +08:00
|
|
|
|
});
|
2022-06-29 08:22:26 +08:00
|
|
|
|
return that;
|
2022-06-21 00:25:07 +08:00
|
|
|
|
};
|
2022-06-19 02:10:15 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 获取节点的 style 属性值
|
|
|
|
|
* currentStyle.getAttribute 参数为 camelCase 形式的字符串
|
|
|
|
|
* @param {HTMLElement} node - 节点
|
|
|
|
|
* @param {string} name - 属性名
|
|
|
|
|
* @returns 属性值
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.getStyle = function(node, name) {
|
|
|
|
|
var style = node.currentStyle ? node.currentStyle : window.getComputedStyle(node, null);
|
2025-01-20 10:25:36 +08:00
|
|
|
|
return style.getPropertyValue
|
|
|
|
|
? style.getPropertyValue(name)
|
2024-12-30 13:50:34 +08:00
|
|
|
|
: style.getAttribute(name.replace(/-(\w)/g, function(_, c){ return c ? c.toUpperCase() : '';}));
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* CSS 外部加载器
|
|
|
|
|
* @param {string} href - 外部 CSS 文件路径
|
|
|
|
|
* @param {Function} callback - 回调函数
|
|
|
|
|
* @param {string} id - 定义 link 标签的 id
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.link = function(href, callback, id) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var head = document.getElementsByTagName('head')[0];
|
|
|
|
|
var link = document.createElement('link');
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 若第二个参数为 string 类型,则该参数为 id
|
|
|
|
|
if (typeof callback === 'string') {
|
|
|
|
|
id = callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 若加载多个
|
|
|
|
|
if (typeof href === 'object') {
|
|
|
|
|
var isArr = that.type(id) === 'array';
|
|
|
|
|
return that.each(href, function(index, value){
|
|
|
|
|
that.link(
|
|
|
|
|
value,
|
|
|
|
|
index === href.length - 1 && callback,
|
|
|
|
|
isArr && id[index]
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 若为传入 id ,则取路径 `//` 后面的字符拼接为 id,不含.与参数
|
|
|
|
|
id = id || href.replace(/^(#|(http(s?)):\/\/|\/\/)|\.|\/|\?.+/g, '');
|
|
|
|
|
id = 'layuicss-'+ id;
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
link.href = href + (config.debug ? '?v='+new Date().getTime() : '');
|
2023-05-18 13:24:53 +08:00
|
|
|
|
link.rel = 'stylesheet';
|
|
|
|
|
link.id = id;
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 插入节点
|
|
|
|
|
if (!document.getElementById(id)) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
head.appendChild(link);
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 是否执行回调
|
|
|
|
|
if (typeof callback !== 'function') {
|
|
|
|
|
return that;
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
onNodeLoad(link, function() {
|
|
|
|
|
callback(link);
|
|
|
|
|
}, function() {
|
|
|
|
|
error(href + ' load error', 'error');
|
|
|
|
|
head.removeChild(link); // 移除节点
|
|
|
|
|
});
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return that;
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* CSS 内部加载器
|
|
|
|
|
* @param {string} modName - 模块名
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.addcss = function(modName, callback, id) {
|
|
|
|
|
return layui.link(config.dir + 'css/' + modName, callback, id);
|
2021-04-22 10:22:45 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 获取执行定义模块时的回调函数,factory 为向下兼容
|
|
|
|
|
* @param {string} modName - 模块名
|
|
|
|
|
* @returns {Function}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.factory = function(modName) {
|
|
|
|
|
if (layui[modName]) {
|
2023-11-14 22:14:19 +08:00
|
|
|
|
return typeof config.callback[modName] === 'function'
|
2018-01-03 09:55:45 +08:00
|
|
|
|
? config.callback[modName]
|
|
|
|
|
: null;
|
|
|
|
|
}
|
|
|
|
|
};
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 图片预加载
|
|
|
|
|
* @param {string} url - 图片路径
|
|
|
|
|
* @param {Function} callback - 成功回调
|
|
|
|
|
* @param {Function} error - 错误回调
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.img = function(url, callback, error) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
var img = new Image();
|
2023-11-14 22:14:19 +08:00
|
|
|
|
img.src = url;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (img.complete) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return callback(img);
|
|
|
|
|
}
|
|
|
|
|
img.onload = function(){
|
|
|
|
|
img.onload = null;
|
2018-05-05 16:59:53 +08:00
|
|
|
|
typeof callback === 'function' && callback(img);
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
|
|
|
|
img.onerror = function(e){
|
|
|
|
|
img.onerror = null;
|
2018-05-05 16:59:53 +08:00
|
|
|
|
typeof error === 'function' && error(e);
|
2023-11-14 22:14:19 +08:00
|
|
|
|
};
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* location.hash 路由解析
|
|
|
|
|
* @param {string} hash 值
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.router = Class.prototype.hash = function(hash) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
|
|
|
|
var hash = hash || location.hash;
|
|
|
|
|
var data = {
|
|
|
|
|
path: [],
|
|
|
|
|
search: {},
|
2025-01-20 10:25:36 +08:00
|
|
|
|
hash: (hash.match(/[^#](#.*$)/) || [])[1] || '',
|
|
|
|
|
href: ''
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-01-20 10:25:36 +08:00
|
|
|
|
if (!/^#/.test(hash)) return data; // 禁止非路由规范
|
2023-05-04 10:17:04 +08:00
|
|
|
|
|
2025-01-20 10:25:36 +08:00
|
|
|
|
hash = hash.replace(/^#/, '');
|
|
|
|
|
data.href = hash;
|
2018-01-03 09:55:45 +08:00
|
|
|
|
hash = hash.replace(/([^#])(#.*$)/, '$1').split('/') || [];
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 提取 Hash 结构
|
2025-03-14 18:42:30 +08:00
|
|
|
|
that.each(hash, function(index, item) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
/^\w+=/.test(item) ? function(){
|
|
|
|
|
item = item.split('=');
|
|
|
|
|
data.search[item[0]] = item[1];
|
|
|
|
|
}() : data.path.push(item);
|
|
|
|
|
});
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return data;
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* URL 解析
|
|
|
|
|
* @param {string} href - url 路径
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.url = function(href) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
|
|
|
|
var data = {
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 提取 url 路径
|
2025-03-14 18:42:30 +08:00
|
|
|
|
pathname: function() {
|
2020-01-15 06:30:00 +08:00
|
|
|
|
var pathname = href
|
|
|
|
|
? function(){
|
2020-11-26 22:12:46 +08:00
|
|
|
|
var str = (href.match(/\.[^.]+?\/.+/) || [])[0] || '';
|
|
|
|
|
return str.replace(/^[^\/]+/, '').replace(/\?.+/, '');
|
2020-01-15 06:30:00 +08:00
|
|
|
|
}()
|
|
|
|
|
: location.pathname;
|
|
|
|
|
return pathname.replace(/^\//, '').split('/');
|
2023-05-04 10:17:04 +08:00
|
|
|
|
}(),
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 提取 url 参数
|
2023-05-04 10:17:04 +08:00
|
|
|
|
search: function(){
|
|
|
|
|
var obj = {};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
var search = (href
|
2020-11-26 22:12:46 +08:00
|
|
|
|
? function(){
|
|
|
|
|
var str = (href.match(/\?.+/) || [])[0] || '';
|
|
|
|
|
return str.replace(/\#.+/, '');
|
|
|
|
|
}()
|
2020-01-15 06:30:00 +08:00
|
|
|
|
: location.search
|
2023-04-30 01:10:55 +08:00
|
|
|
|
).replace(/^\?+/, '').split('&'); // 去除 ?,按 & 分割参数
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 遍历分割后的参数
|
2025-03-14 18:42:30 +08:00
|
|
|
|
that.each(search, function(index, item) {
|
|
|
|
|
var _index = item.indexOf('=');
|
|
|
|
|
var key = function() { // 提取 key
|
|
|
|
|
if (_index < 0) {
|
2020-01-15 06:30:00 +08:00
|
|
|
|
return item.substr(0, item.length);
|
2025-03-14 18:42:30 +08:00
|
|
|
|
} else if(_index === 0) {
|
2020-01-15 06:30:00 +08:00
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return item.substr(0, _index);
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
}();
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 提取 value
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (key) {
|
2020-01-15 06:30:00 +08:00
|
|
|
|
obj[key] = _index > 0 ? item.substr(_index + 1) : null;
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2020-01-15 06:30:00 +08:00
|
|
|
|
return obj;
|
2023-05-04 10:17:04 +08:00
|
|
|
|
}(),
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 提取 Hash
|
2025-03-14 18:42:30 +08:00
|
|
|
|
hash: that.router(function() {
|
2023-11-14 22:14:19 +08:00
|
|
|
|
return href
|
2021-05-08 06:31:19 +08:00
|
|
|
|
? ((href.match(/#.+/) || [])[0] || '/')
|
2020-01-15 06:30:00 +08:00
|
|
|
|
: location.hash;
|
|
|
|
|
}())
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2020-01-15 06:30:00 +08:00
|
|
|
|
return data;
|
|
|
|
|
};
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 本地持久存储
|
|
|
|
|
* @param {string} table - 表名
|
|
|
|
|
* @param {Object} settings - 设置项
|
|
|
|
|
* @param {Storage} storage - 存储对象,localStorage 或 sessionStorage
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.data = function(table, settings, storage) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
table = table || 'layui';
|
2018-01-03 09:55:45 +08:00
|
|
|
|
storage = storage || localStorage;
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2022-07-03 21:32:50 +08:00
|
|
|
|
// 如果 settings 为 null,则删除表
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (settings === null) {
|
2018-01-03 09:55:45 +08:00
|
|
|
|
return delete storage[table];
|
2017-08-21 08:51:13 +08:00
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
|
|
|
|
settings = typeof settings === 'object'
|
|
|
|
|
? settings
|
2017-08-21 08:51:13 +08:00
|
|
|
|
: {key: settings};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-05-04 10:17:04 +08:00
|
|
|
|
try {
|
2018-01-03 09:55:45 +08:00
|
|
|
|
var data = JSON.parse(storage[table]);
|
2023-05-04 10:17:04 +08:00
|
|
|
|
} catch(e) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
var data = {};
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if ('value' in settings) data[settings.key] = settings.value;
|
|
|
|
|
if (settings.remove) delete data[settings.key];
|
2018-01-03 09:55:45 +08:00
|
|
|
|
storage[table] = JSON.stringify(data);
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return settings.key ? data[settings.key] : data;
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 本地临时存储
|
|
|
|
|
* @param {string} table - 表名
|
|
|
|
|
* @param {Object} settings - 设置项
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.sessionData = function(table, settings) {
|
2018-01-03 09:55:45 +08:00
|
|
|
|
return this.data(table, settings, sessionStorage);
|
|
|
|
|
}
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 设备信息
|
|
|
|
|
* @param {string} key - 任意 key
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.device = function(key) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var agent = navigator.userAgent.toLowerCase();
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 获取版本号
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var getVersion = function(label) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
var exp = new RegExp(label + '/([^\\s\\_\\-]+)');
|
|
|
|
|
label = (agent.match(exp)||[])[1];
|
|
|
|
|
return label || false;
|
2023-05-04 10:17:04 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 返回结果集
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var result = {
|
2025-03-14 18:42:30 +08:00
|
|
|
|
os: function() { // 底层操作系统
|
|
|
|
|
if (/windows/.test(agent)) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return 'windows';
|
2025-03-14 18:42:30 +08:00
|
|
|
|
} else if(/linux/.test(agent)) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return 'linux';
|
2025-03-14 18:42:30 +08:00
|
|
|
|
} else if(/iphone|ipod|ipad|ios/.test(agent)) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return 'ios';
|
2025-03-14 18:42:30 +08:00
|
|
|
|
} else if(/mac/.test(agent)) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return 'mac';
|
2023-11-14 22:14:19 +08:00
|
|
|
|
}
|
2023-05-04 10:17:04 +08:00
|
|
|
|
}(),
|
2025-03-14 18:42:30 +08:00
|
|
|
|
ie: function() { // ie 版本
|
|
|
|
|
return (!!window.ActiveXObject || "ActiveXObject" in window) ? (
|
2023-04-30 01:10:55 +08:00
|
|
|
|
(agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于 ie11 并没有 msie 的标识
|
2017-08-21 08:51:13 +08:00
|
|
|
|
) : false;
|
2023-05-04 10:17:04 +08:00
|
|
|
|
}(),
|
|
|
|
|
weixin: getVersion('micromessenger') // 是否微信
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 任意的 key
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (key && !result[key]) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
result[key] = getVersion(key);
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 移动设备
|
2017-08-21 08:51:13 +08:00
|
|
|
|
result.android = /android/.test(agent);
|
|
|
|
|
result.ios = result.os === 'ios';
|
2023-06-17 23:33:54 +08:00
|
|
|
|
result.mobile = (result.android || result.ios);
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 提示
|
2025-03-14 18:42:30 +08:00
|
|
|
|
Class.prototype.hint = function() {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return {
|
|
|
|
|
error: error
|
2021-05-18 02:42:31 +08:00
|
|
|
|
};
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* typeof 类型细分 -> string/number/boolean/undefined/null、object/array/function/…
|
|
|
|
|
* @param {*} operand - 任意值
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype._typeof = Class.prototype.type = function(operand) {
|
2021-05-18 02:42:31 +08:00
|
|
|
|
if(operand === null) return String(operand);
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 细分引用类型
|
2025-03-14 18:42:30 +08:00
|
|
|
|
return (typeof operand === 'object' || typeof operand === 'function') ? function() {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var type = Object.prototype.toString.call(operand).match(/\s(.+)\]$/) || []; // 匹配类型字符
|
|
|
|
|
var classType = 'Function|Array|Date|RegExp|Object|Error|Symbol'; // 常见类型字符
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2021-05-18 02:42:31 +08:00
|
|
|
|
type = type[1] || 'Object';
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 除匹配到的类型外,其他对象均返回 object
|
2023-11-14 22:14:19 +08:00
|
|
|
|
return new RegExp('\\b('+ classType + ')\\b').test(type)
|
|
|
|
|
? type.toLowerCase()
|
2021-05-18 02:42:31 +08:00
|
|
|
|
: 'object';
|
|
|
|
|
}() : typeof operand;
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 对象是否具备数组结构(此处为兼容 jQuery 对象)
|
|
|
|
|
* @param {Object} obj - 任意对象
|
|
|
|
|
* @returns {boolean}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype._isArray = Class.prototype.isArray = function(obj) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
|
|
|
|
var len;
|
|
|
|
|
var type = that.type(obj);
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (!obj || (typeof obj !== 'object') || obj === window) return false;
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
len = 'length' in obj && obj.length; // 兼容 ie
|
2021-05-18 02:42:31 +08:00
|
|
|
|
return type === 'array' || len === 0 || (
|
2023-04-30 01:10:55 +08:00
|
|
|
|
typeof len === 'number' && len > 0 && (len - 1) in obj // 兼容 jQuery 对象
|
2021-05-18 02:42:31 +08:00
|
|
|
|
);
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 遍历
|
|
|
|
|
* @param {Object} obj - 任意对象
|
|
|
|
|
* @param {Function} fn - 遍历回调
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.each = function(obj, fn) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var key;
|
|
|
|
|
var that = this;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var callback = function(key, obj) {
|
|
|
|
|
return fn.call(obj[key], key, obj[key]);
|
2021-05-08 06:31:19 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (typeof fn !== 'function') {
|
|
|
|
|
return that;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
obj = obj || [];
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 优先处理数组结构
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (that.isArray(obj)) {
|
|
|
|
|
for (key = 0; key < obj.length; key++) {
|
|
|
|
|
if(callback(key, obj)) break;
|
2017-08-21 08:51:13 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-03-14 18:42:30 +08:00
|
|
|
|
for (key in obj) {
|
|
|
|
|
if(callback(key, obj)) break;
|
2017-08-21 08:51:13 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return that;
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 将数组中的成员对象按照某个 key 的 value 值进行排序
|
|
|
|
|
* @param {Object[]} arr - 任意数组
|
|
|
|
|
* @param {string} key - 任意 key
|
|
|
|
|
* @param {boolean} desc - 是否降序
|
|
|
|
|
* @param {boolean} notClone - 是否不对 arr 进行克隆
|
|
|
|
|
* @returns {Object[]}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.sort = function(arr, key, desc, notClone) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
|
|
|
|
var clone = notClone ? (arr || []) : JSON.parse(
|
2022-05-18 22:35:13 +08:00
|
|
|
|
JSON.stringify(arr || [])
|
2017-08-21 08:51:13 +08:00
|
|
|
|
);
|
2023-04-28 16:31:11 +08:00
|
|
|
|
|
2022-05-18 22:35:13 +08:00
|
|
|
|
// 若未传入 key,则直接返回原对象
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (that.type(arr) === 'object' && !key) {
|
2022-05-18 22:35:13 +08:00
|
|
|
|
return clone;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
} else if(typeof arr !== 'object') { // 若 arr 非对象
|
2022-05-18 22:35:13 +08:00
|
|
|
|
return [clone];
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2022-05-18 22:35:13 +08:00
|
|
|
|
// 开始排序
|
2025-03-14 18:42:30 +08:00
|
|
|
|
clone.sort(function(o1, o2) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var v1 = o1[key];
|
|
|
|
|
var v2 = o2[key];
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2022-05-18 22:35:13 +08:00
|
|
|
|
/*
|
|
|
|
|
* 特殊数据
|
|
|
|
|
* 若比较的成员均非对象
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// 若比较的成员均为数字
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (!isNaN(o1) && !isNaN(o2)) return o1 - o2;
|
|
|
|
|
|
2022-05-18 22:35:13 +08:00
|
|
|
|
// 若比较的成员只存在某一个非对象
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (!isNaN(o1) && isNaN(o2)) {
|
2022-05-18 22:35:13 +08:00
|
|
|
|
if(key && typeof o2 === 'object'){
|
|
|
|
|
v1 = o1;
|
|
|
|
|
} else {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2025-03-14 18:42:30 +08:00
|
|
|
|
} else if (isNaN(o1) && !isNaN(o2)) {
|
|
|
|
|
if (key && typeof o1 === 'object') {
|
2022-05-18 22:35:13 +08:00
|
|
|
|
v2 = o2;
|
|
|
|
|
} else {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 正常数据
|
|
|
|
|
* 即成员均为对象,也传入了对比依据: key
|
|
|
|
|
* 若 value 为数字,按「大小」排序;若 value 非数字,则按「字典序」排序
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// value 是否为数字
|
|
|
|
|
var isNum = [!isNaN(v1), !isNaN(v2)];
|
|
|
|
|
|
|
|
|
|
// 若为数字比较
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (isNum[0] && isNum[1]) {
|
|
|
|
|
if(v1 && (!v2 && v2 !== 0)) { // 数字 vs 空
|
2021-05-31 08:57:00 +08:00
|
|
|
|
return 1;
|
2025-03-14 18:42:30 +08:00
|
|
|
|
} else if((!v1 && v1 !== 0) && v2) { // 空 vs 数字
|
2021-05-31 08:57:00 +08:00
|
|
|
|
return -1;
|
2023-04-30 01:10:55 +08:00
|
|
|
|
} else { // 数字 vs 数字
|
2021-05-31 08:57:00 +08:00
|
|
|
|
return v1 - v2;
|
|
|
|
|
}
|
2022-11-18 08:58:25 +08:00
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2021-05-31 08:57:00 +08:00
|
|
|
|
/**
|
|
|
|
|
* 字典序排序
|
|
|
|
|
*/
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2022-05-18 22:35:13 +08:00
|
|
|
|
// 若为非数字比较
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (!isNum[0] && !isNum[1]) {
|
2022-05-18 22:35:13 +08:00
|
|
|
|
// 字典序比较
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (v1 > v2) {
|
2021-05-31 08:57:00 +08:00
|
|
|
|
return 1;
|
|
|
|
|
} else if (v1 < v2) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2022-05-18 22:35:13 +08:00
|
|
|
|
// 若为混合比较
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (isNum[0] || !isNum[1]) { // 数字 vs 非数字
|
2021-05-31 08:57:00 +08:00
|
|
|
|
return -1;
|
2023-04-30 01:10:55 +08:00
|
|
|
|
} else if(!isNum[0] || isNum[1]) { // 非数字 vs 数字
|
2021-05-31 08:57:00 +08:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-18 22:35:13 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
});
|
2017-08-30 17:10:33 +08:00
|
|
|
|
|
2022-05-18 22:35:13 +08:00
|
|
|
|
desc && clone.reverse(); // 倒序
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return clone;
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 阻止事件冒泡
|
|
|
|
|
* @param {Event} thisEvent - 事件对象
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.stope = function(thisEvent) {
|
|
|
|
|
try {
|
|
|
|
|
thisEvent.stopPropagation();
|
|
|
|
|
} catch(e) {
|
2018-01-03 09:55:45 +08:00
|
|
|
|
thisEvent.cancelBubble = true;
|
|
|
|
|
}
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 字符常理
|
2021-05-18 02:42:31 +08:00
|
|
|
|
var EV_REMOVE = 'LAYUI-EVENT-REMOVE';
|
2017-08-21 08:51:13 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 自定义模块事件
|
|
|
|
|
* @param {string} modName - 模块名
|
|
|
|
|
* @param {string} events - 事件名
|
|
|
|
|
* @param {Function} callback - 回调
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.onevent = function(modName, events, callback) {
|
|
|
|
|
if (typeof modName !== 'string' || typeof callback !== 'function') {
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
return Class.event(modName, events, null, callback);
|
2017-08-21 08:51:13 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 执行自定义模块事件
|
|
|
|
|
* @param {string} modName - 模块名
|
|
|
|
|
* @param {string} events - 事件名
|
|
|
|
|
* @param {Object} params - 参数
|
|
|
|
|
* @param {Function} fn - 回调
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.event = Class.event = function(modName, events, params, fn) {
|
2023-05-04 10:17:04 +08:00
|
|
|
|
var that = this;
|
|
|
|
|
var result = null;
|
|
|
|
|
var filter = (events || '').match(/\((.*)\)$/)||[]; // 提取事件过滤器字符结构,如:select(xxx)
|
|
|
|
|
var eventName = (modName + '.'+ events).replace(filter[0], ''); // 获取事件名称,如:form.select
|
2025-03-14 18:42:30 +08:00
|
|
|
|
var filterName = filter[1] || ''; // 获取过滤器名称, 如:xxx
|
|
|
|
|
var callback = function(_, item) {
|
2017-08-21 08:51:13 +08:00
|
|
|
|
var res = item && item.call(that, params);
|
|
|
|
|
res === false && result === null && (result = false);
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 如果参数传入特定字符,则执行移除事件
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (params === EV_REMOVE) {
|
2020-11-26 22:12:46 +08:00
|
|
|
|
delete (that.cache.event[eventName] || {})[filterName];
|
|
|
|
|
return that;
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 添加事件
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (fn) {
|
|
|
|
|
cache.event[eventName] = cache.event[eventName] || {};
|
2018-01-03 09:55:45 +08:00
|
|
|
|
|
2022-09-20 16:33:35 +08:00
|
|
|
|
if (filterName) {
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 带 filter 不支持重复事件
|
|
|
|
|
cache.event[eventName][filterName] = [fn];
|
2022-09-20 16:33:35 +08:00
|
|
|
|
} else {
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// 不带 filter 处理的是所有的同类事件,应该支持重复事件
|
|
|
|
|
cache.event[eventName][filterName] = cache.event[eventName][filterName] || [];
|
|
|
|
|
cache.event[eventName][filterName].push(fn);
|
2022-09-20 16:33:35 +08:00
|
|
|
|
}
|
2018-01-03 09:55:45 +08:00
|
|
|
|
return this;
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 执行事件回调
|
2025-03-14 18:42:30 +08:00
|
|
|
|
layui.each(cache.event[eventName], function(key, item) {
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 执行当前模块的全部事件
|
2025-03-14 18:42:30 +08:00
|
|
|
|
if (filterName === '{*}') {
|
2018-01-03 09:55:45 +08:00
|
|
|
|
layui.each(item, callback);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2023-04-30 01:10:55 +08:00
|
|
|
|
// 执行指定事件
|
2018-01-03 09:55:45 +08:00
|
|
|
|
key === '' && layui.each(item, callback);
|
2018-11-01 02:50:21 +08:00
|
|
|
|
(filterName && key === filterName) && layui.each(item, callback);
|
2018-01-03 09:55:45 +08:00
|
|
|
|
});
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2017-08-21 08:51:13 +08:00
|
|
|
|
return result;
|
|
|
|
|
};
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 新增模块事件
|
|
|
|
|
* @param {string} events - 事件名
|
|
|
|
|
* @param {string} modName - 模块名
|
|
|
|
|
* @param {Function} callback - 回调
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.on = function(events, modName, callback) {
|
2020-11-26 22:12:46 +08:00
|
|
|
|
var that = this;
|
|
|
|
|
return that.onevent.call(that, modName, events, callback);
|
|
|
|
|
}
|
2023-11-14 22:14:19 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 移除模块事件
|
|
|
|
|
* @param {string} events - 事件名
|
|
|
|
|
* @param {string} modName - 模块名
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.off = function(events, modName) {
|
2020-11-26 22:12:46 +08:00
|
|
|
|
var that = this;
|
2021-05-18 02:42:31 +08:00
|
|
|
|
return that.event.call(that, modName, events, EV_REMOVE);
|
2020-11-26 22:12:46 +08:00
|
|
|
|
};
|
2023-05-06 17:42:38 +08:00
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 防抖
|
|
|
|
|
* @param {Function} func - 回调
|
|
|
|
|
* @param {number} wait - 延时执行的毫秒数
|
|
|
|
|
* @returns {Function}
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.debounce = function (func, wait) {
|
2023-05-06 17:42:38 +08:00
|
|
|
|
var timeout;
|
|
|
|
|
return function () {
|
|
|
|
|
var context = this;
|
|
|
|
|
var args = arguments;
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
timeout = setTimeout(function () {
|
|
|
|
|
func.apply(context, args);
|
|
|
|
|
}, wait);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
/**
|
|
|
|
|
* 节流
|
|
|
|
|
* @param {Function} func - 回调
|
|
|
|
|
* @param {number} wait - 不重复执行的毫秒数
|
|
|
|
|
*/
|
|
|
|
|
Class.prototype.throttle = function (func, wait) {
|
2023-05-06 17:42:38 +08:00
|
|
|
|
var cooldown = false;
|
|
|
|
|
return function () {
|
|
|
|
|
var context = this;
|
|
|
|
|
var args = arguments;
|
|
|
|
|
if (!cooldown) {
|
|
|
|
|
func.apply(context, args);
|
|
|
|
|
cooldown = true;
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
cooldown = false;
|
|
|
|
|
}, wait);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-14 18:42:30 +08:00
|
|
|
|
// export layui
|
|
|
|
|
window.layui = new Class();
|
|
|
|
|
})(window);
|