layui/src/layui.js
2025-04-15 14:59:09 +08:00

1025 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Layui
* Classic modular front-end UI library
* MIT Licensed
*/
(function(window) {
'use strict';
// 便于打包时的字符压缩
var document = window.document;
var location = window.location;
// 基础配置
var config = {
timeout: 10, // 符合规范的模块请求最长等待秒数
debug: false, // 是否开启调试模式
version: false // 是否在模块请求时加入版本号参数(以更新模块缓存)
};
// 模块加载缓存信息
var cache = {
modules: {}, // 模块物理路径
status: {}, // 模块加载就绪状态
event: {}, // 模块自定义事件
callback: {} // 模块的回调
};
// constructor
var Class = function() {
this.v = '2.11.0-rc.3'; // 版本号
};
// 识别预先可能定义的指定全局对象
var GLOBAL = window.LAYUI_GLOBAL || {};
// 获取 layui 所在目录
var getPath = function() {
var jsPath = (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') ? document.currentScript.src : function(){
var js = document.getElementsByTagName('script');
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 config.dir = GLOBAL.dir || jsPath.substring(0, jsPath.lastIndexOf('/') + 1);
}();
// 异常提示
var error = function(msg, type) {
type = type || 'log';
window.console && console[type] && console[type]('layui error hint: ' + msg);
};
// 内置模块
var builtinModules = config.builtin = {
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', // 树表
tabs: 'tabs', // 标签页
element: 'element', // 常用元素操作
rate: 'rate', // 评分组件
colorpicker: 'colorpicker', // 颜色选择器
slider: 'slider', // 滑块
carousel: 'carousel', // 轮播
flow: 'flow', // 流加载
util: 'util', // 工具块
code: 'code', // 代码修饰器
jquery: 'jquery', // DOM 库(第三方)
component: 'component', // 组件构建器
all: 'all',
'layui.all': 'layui.all' // 聚合标识(功能性的,非真实模块)
};
/**
* 低版本浏览器适配
* @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;
};
/**
* 定义模块
* @param {(string|string[])} deps - 依赖的模块列表
* @param {Function} callback - 模块的回调
*/
Class.prototype.define = function(deps, callback) {
var that = this;
var useCallback = function() {
var setModule = function(mod, exports) {
layui[mod] = exports; // 将模块接口赋值在 layui 对象中
cache.status[mod] = true; // 标记模块注册完成
};
// 执行模块的回调
typeof callback === 'function' && callback(function(mod, exports) {
setModule(mod, exports);
// 记录模块回调,以便需要时再执行
cache.callback[mod] = function() {
callback(setModule);
}
});
return this;
};
// 若未依赖模块
if (typeof deps === 'function') {
callback = deps;
deps = [];
}
that.use(deps, useCallback, null, 'define');
return that;
};
/**
* 使用模块
* @param {(string|string[])} mods - 模块列表
* @param {Function} callback - 回调
*/
Class.prototype.use = function(mods, callback, exports, from) {
var that = this;
var dir = config.dir = config.dir ? config.dir : getPath;
// 整理模块队列
mods = (function() {
if (typeof mods === 'string') {
return [mods];
}
// 若第一个参数为 function ,则自动加载所有内置模块,且执行的回调即为该 function 参数;
else if(typeof mods === 'function') {
callback = mods;
return ['all'];
}
return mods;
})();
// 获取 layui 静态资源所在 host
if (!config.host) {
config.host = (dir.match(/\/\/([\s\S]+?)\//)||['//'+ location.host +'/'])[0];
}
// 若参数异常
if (!mods) return that;
// 若页面已经存在 jQuery 且所定义的模块依赖 jQuery则不加载内部 jquery 模块
if (window.jQuery && jQuery.fn.on) {
that.each(mods, function(index, item) {
if (item === 'jquery') {
mods.splice(index, 1);
}
});
layui.jquery = layui.$ = window.jQuery;
}
// 将模块的接口作为回调的参数传递
exports = exports || [];
// 加载当前队列的第一个模块
var item = mods[0];
var modInfo = that.modules[item]; // 当前模块信息
// 是否为外部模块,即无需遵循 layui 轻量级模块规范的任意第三方组件。
var isExternalModule = typeof modInfo === 'object';
// 回调触发
var onCallback = function () {
exports.push(layui[item]);
mods.length > 1
? that.use(mods.slice(1), callback, exports, from)
: (typeof callback === 'function' && function() {
// 保证文档加载完毕再执行回调
if(layui.jquery && typeof layui.jquery === 'function' && from !== 'define'){
return layui.jquery(function(){
callback.apply(layui, exports);
});
}
callback.apply(layui, exports);
}() );
};
// 回调轮询
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])) {
return onCallback(), that;
}
// 当前模块所在路径
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
}
// 首次加载模块
if (!cache.modules[item]) {
var head = document.getElementsByTagName('head')[0];
var node = document.createElement('script');
node.async = true;
node.charset = 'utf-8'; // 避免 IE9 的编码问题
node.src = url + function() {
var version = config.version === true
? (config.v || (new Date()).getTime())
: (config.version || '');
return version ? ('?v=' + version) : '';
}();
head.appendChild(node);
// 节点加载事件
onNodeLoad(node, function() {
head.removeChild(node);
pollCallback();
}, function() {
head.removeChild(node);
});
// 模块已首次加载的标记
cache.modules[item] = url;
} else { // 再次 use 模块
pollCallback();
}
return that;
};
// 记录全部模块
Class.prototype.modules = Object.assign({}, builtinModules);
/**
* 拓展模块
* @param {Object} settings - 拓展模块的配置
*/
Class.prototype.extend = function(settings) {
var that = this;
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;
}
}
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) {
delete that[item];
delete builtinModules[item];
delete that.modules[item];
delete cache.status[item];
delete cache.modules[item];
});
return that;
};
/**
* 获取节点的 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);
return style.getPropertyValue
? style.getPropertyValue(name)
: style.getAttribute(name.replace(/-(\w)/g, function(_, c){ return c ? c.toUpperCase() : '';}));
};
/**
* CSS 外部加载器
* @param {string} href - 外部 CSS 文件路径
* @param {Function} callback - 回调函数
* @param {string} id - 定义 link 标签的 id
*/
Class.prototype.link = function(href, callback, id) {
var that = this;
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
// 若第二个参数为 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]
);
});
}
// 若为传入 id ,则取路径 `//` 后面的字符拼接为 id不含.与参数
id = id || href.replace(/^(#|(http(s?)):\/\/|\/\/)|\.|\/|\?.+/g, '');
id = 'layuicss-'+ id;
link.href = href + (config.debug ? '?v='+new Date().getTime() : '');
link.rel = 'stylesheet';
link.id = id;
// 插入节点
if (!document.getElementById(id)) {
head.appendChild(link);
}
// 是否执行回调
if (typeof callback !== 'function') {
return that;
}
onNodeLoad(link, function() {
callback(link);
}, function() {
error(href + ' load error', 'error');
head.removeChild(link); // 移除节点
});
return that;
};
/**
* CSS 内部加载器
* @param {string} modName - 模块名
*/
Class.prototype.addcss = function(modName, callback, id) {
return layui.link(config.dir + 'css/' + modName, callback, id);
};
/**
* 获取执行定义模块时的回调函数factory 为向下兼容
* @param {string} modName - 模块名
* @returns {Function}
*/
Class.prototype.factory = function(modName) {
if (layui[modName]) {
return typeof config.callback[modName] === 'function'
? config.callback[modName]
: null;
}
};
/**
* 图片预加载
* @param {string} url - 图片路径
* @param {Function} callback - 成功回调
* @param {Function} error - 错误回调
*/
Class.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);
};
};
/**
* location.hash 路由解析
* @param {string} hash 值
* @returns {Object}
*/
Class.prototype.router = Class.prototype.hash = function(hash) {
var that = this;
var hash = hash || location.hash;
var data = {
path: [],
search: {},
hash: (hash.match(/[^#](#.*$)/) || [])[1] || '',
href: ''
};
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;
};
/**
* URL 解析
* @param {string} href - url 路径
* @returns {Object}
*/
Class.prototype.url = function(href) {
var that = this;
var data = {
// 提取 url 路径
pathname: function() {
var pathname = href
? function(){
var str = (href.match(/\.[^.]+?\/.+/) || [])[0] || '';
return str.replace(/^[^\/]+/, '').replace(/\?.+/, '');
}()
: location.pathname;
return pathname.replace(/^\//, '').split('/');
}(),
// 提取 url 参数
search: function(){
var obj = {};
var search = (href
? function(){
var str = (href.match(/\?.+/) || [])[0] || '';
return str.replace(/\#.+/, '');
}()
: location.search
).replace(/^\?+/, '').split('&'); // 去除 ?,按 & 分割参数
// 遍历分割后的参数
that.each(search, function(index, item) {
var _index = item.indexOf('=');
var key = function() { // 提取 key
if (_index < 0) {
return item.substr(0, item.length);
} else if(_index === 0) {
return false;
} else {
return item.substr(0, _index);
}
}();
// 提取 value
if (key) {
obj[key] = _index > 0 ? item.substr(_index + 1) : null;
}
});
return obj;
}(),
// 提取 Hash
hash: that.router(function() {
return href
? ((href.match(/#.+/) || [])[0] || '/')
: location.hash;
}())
};
return data;
};
/**
* 本地持久存储
* @param {string} table - 表名
* @param {Object} settings - 设置项
* @param {Storage} storage - 存储对象localStorage 或 sessionStorage
* @returns {Object}
*/
Class.prototype.data = function(table, settings, storage) {
table = table || 'layui';
storage = storage || localStorage;
// 如果 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;
};
/**
* 本地临时存储
* @param {string} table - 表名
* @param {Object} settings - 设置项
* @returns {Object}
*/
Class.prototype.sessionData = function(table, settings) {
return this.data(table, settings, sessionStorage);
}
/**
* 设备信息
* @param {string} key - 任意 key
* @returns {Object}
*/
Class.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 (!!window.ActiveXObject || "ActiveXObject" in window) ? (
(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';
result.mobile = (result.android || result.ios);
return result;
};
// 提示
Class.prototype.hint = function() {
return {
error: error
};
};
/**
* typeof 类型细分 -> string/number/boolean/undefined/null、object/array/function/…
* @param {*} operand - 任意值
* @returns {string}
*/
Class.prototype._typeof = Class.prototype.type = function(operand) {
if(operand === null) return String(operand);
// 细分引用类型
return (typeof operand === 'object' || typeof operand === 'function') ? function() {
var type = Object.prototype.toString.call(operand).match(/\s(.+)\]$/) || []; // 匹配类型字符
var classType = 'Function|Array|Date|RegExp|Object|Error|Symbol'; // 常见类型字符
type = type[1] || 'Object';
// 除匹配到的类型外,其他对象均返回 object
return new RegExp('\\b('+ classType + ')\\b').test(type)
? type.toLowerCase()
: 'object';
}() : typeof operand;
};
/**
* 对象是否具备数组结构(此处为兼容 jQuery 对象)
* @param {Object} obj - 任意对象
* @returns {boolean}
*/
Class.prototype._isArray = Class.prototype.isArray = function(obj) {
var that = this;
var len;
var type = that.type(obj);
if (!obj || (typeof obj !== 'object') || obj === window) return false;
len = 'length' in obj && obj.length; // 兼容 ie
return type === 'array' || len === 0 || (
typeof len === 'number' && len > 0 && (len - 1) in obj // 兼容 jQuery 对象
);
};
/**
* 遍历
* @param {Object} obj - 任意对象
* @param {Function} fn - 遍历回调
*/
Class.prototype.each = function(obj, fn) {
var key;
var that = this;
var callback = function(key, obj) {
return fn.call(obj[key], key, obj[key]);
};
if (typeof fn !== 'function') {
return that;
}
obj = obj || [];
// 优先处理数组结构
if (that.isArray(obj)) {
for (key = 0; key < obj.length; key++) {
if(callback(key, obj)) break;
}
} else {
for (key in obj) {
if(callback(key, obj)) break;
}
}
return that;
};
/**
* 将数组中的成员对象按照某个 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) {
var that = this;
var clone = notClone ? (arr || []) : JSON.parse(
JSON.stringify(arr || [])
);
// 若未传入 key则直接返回原对象
if (that.type(arr) === 'object' && !key) {
return clone;
} else if(typeof arr !== 'object') { // 若 arr 非对象
return [clone];
}
// 开始排序
clone.sort(function(o1, o2) {
var v1 = o1[key];
var v2 = o2[key];
/*
* 特殊数据
* 若比较的成员均非对象
*/
// 若比较的成员均为数字
if (!isNaN(o1) && !isNaN(o2)) return o1 - o2;
// 若比较的成员只存在某一个非对象
if (!isNaN(o1) && isNaN(o2)) {
if(key && typeof o2 === 'object'){
v1 = o1;
} else {
return -1;
}
} else if (isNaN(o1) && !isNaN(o2)) {
if (key && typeof o1 === 'object') {
v2 = o2;
} else {
return 1;
}
}
/*
* 正常数据
* 即成员均为对象,也传入了对比依据: key
* 若 value 为数字,按「大小」排序;若 value 非数字,则按「字典序」排序
*/
// value 是否为数字
var isNum = [!isNaN(v1), !isNaN(v2)];
// 若为数字比较
if (isNum[0] && isNum[1]) {
if(v1 && (!v2 && v2 !== 0)) { // 数字 vs 空
return 1;
} else if((!v1 && v1 !== 0) && v2) { // 空 vs 数字
return -1;
} else { // 数字 vs 数字
return v1 - v2;
}
}
/**
* 字典序排序
*/
// 若为非数字比较
if (!isNum[0] && !isNum[1]) {
// 字典序比较
if (v1 > v2) {
return 1;
} else if (v1 < v2) {
return -1;
} else {
return 0;
}
}
// 若为混合比较
if (isNum[0] || !isNum[1]) { // 数字 vs 非数字
return -1;
} else if(!isNum[0] || isNum[1]) { // 非数字 vs 数字
return 1;
}
});
desc && clone.reverse(); // 倒序
return clone;
};
/**
* 阻止事件冒泡
* @param {Event} thisEvent - 事件对象
*/
Class.prototype.stope = function(thisEvent) {
try {
thisEvent.stopPropagation();
} catch(e) {
thisEvent.cancelBubble = true;
}
};
// 字符常理
var EV_REMOVE = 'LAYUI-EVENT-REMOVE';
/**
* 自定义模块事件
* @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);
};
/**
* 执行自定义模块事件
* @param {string} modName - 模块名
* @param {string} events - 事件名
* @param {Object} params - 参数
* @param {Function} fn - 回调
*/
Class.prototype.event = Class.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 (params === EV_REMOVE) {
delete (that.cache.event[eventName] || {})[filterName];
return that;
}
// 添加事件
if (fn) {
cache.event[eventName] = cache.event[eventName] || {};
if (filterName) {
// 带 filter 不支持重复事件
cache.event[eventName][filterName] = [fn];
} else {
// 不带 filter 处理的是所有的同类事件,应该支持重复事件
cache.event[eventName][filterName] = cache.event[eventName][filterName] || [];
cache.event[eventName][filterName].push(fn);
}
return this;
}
// 执行事件回调
layui.each(cache.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;
};
/**
* 新增模块事件
* @param {string} events - 事件名
* @param {string} modName - 模块名
* @param {Function} callback - 回调
* @returns {Object}
*/
Class.prototype.on = function(events, modName, callback) {
var that = this;
return that.onevent.call(that, modName, events, callback);
}
/**
* 移除模块事件
* @param {string} events - 事件名
* @param {string} modName - 模块名
* @returns {Object}
*/
Class.prototype.off = function(events, modName) {
var that = this;
return that.event.call(that, modName, events, EV_REMOVE);
};
/**
* 防抖
* @param {Function} func - 回调
* @param {number} wait - 延时执行的毫秒数
* @returns {Function}
*/
Class.prototype.debounce = function (func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
func.apply(context, args);
}, wait);
}
};
/**
* 节流
* @param {Function} func - 回调
* @param {number} wait - 不重复执行的毫秒数
*/
Class.prototype.throttle = function (func, wait) {
var cooldown = false;
return function () {
var context = this;
var args = arguments;
if (!cooldown) {
func.apply(context, args);
cooldown = true;
setTimeout(function () {
cooldown = false;
}, wait);
}
}
};
// export layui
window.layui = new Class();
})(window);