一、layui.define 用法
layui.define([mods], callback)
通过layui.define该方法可在新的 JS 文件中定义一个 layui 模块。
- mods 是可选的,用于声明该模块所依赖的模块。
- callback 为模块加载完毕的回调函数,它返回一个 exports 参数,用于输出该模块的接口。
代码示例
layui.define(function(exports){
//do something
exports('demo', {
msg: 'Hello Demo'
});
});
跟 RequireJS 最大不同的地方在于接口输出,exports 是一个函数(exports(模块名,模块接口))。
当你声明了上述的一个模块后,你就可以在外部使用了,demo 就会注册到 layui 对象下,即可通过 var demo = layui.demo 去得到该模块接口。你也可以在定义一个模块的时候,声明该模块所需的依赖,如:
layui.define(['layer', 'laypage', 'mod1'], function(exports){ //此处 mod1 为你的任意扩展模块
//do something
exports('demo', {
msg: 'Hello Demo'
});
});
二、layui.define 源码
Layui.prototype.define = function(deps, factory) {
var that = this; // 存储当前 this
var type = typeof deps === 'function'; // deps 是否为函数
// 定义回调函数
var callback = function () {
// setApp 用于把用户自定义导出的模块注册到实例对象 layui 上, 并标记模块已加载
var setApp = function (app, exports) {
layui[app] = exports; // layui 为实例对象, 在实例中添加自定义模块
config.status[app] = true; // 在congfig中设置模块状态
}
/**
* factory 工厂模式
* app 用户自定义导处模块名
* exports 用户自定义导处的数据
*/
typeof factory === 'function' && factory(function(app, exports) {
// 当前处于匿名函数内, 该匿名函数就是回调函数 exports
setApp(app, exports);
// 存储回调函数 (这里的匿名函数和 define 中 callback 一样), 用于后续如果重新执行模块
config.callback[app] = function(){
factory(setApp);
}
});
return this;
};
// 第一个参数为函数时, 函数赋给 factory,并置为 []
type && (
factory = deps,
deps = []
);
that.use(deps, callback, null, 'define');
return that;
}
三、layui.define 关键代码分析
var type = typeof deps === ‘function’;
判断deps是否是函数。layui.define([mods], callback) 函数使用方法中 mods 是可选参数,第一个参数有可能是函数,例如
layui.define(function(exports){
//do something
exports('demo', {
msg: 'Hello Demo'
});
});
如果是函数 type 为 true,后续会执行函数交换赋值操作。
type && (
factory = deps,
deps = []
);
type 为 true 时, deps 变量中的内容赋值给factory,并且deps为空数组。
that.use(deps, callback, null, ‘define’);
调用use函数,官方文档中没有介绍第三、四参数的用法。use函数用法在layui.use博客中详细说明,这里不用多介绍
callback 回调函数
// 定义回调函数
var callback = function () {
// setApp 用于把用户自定义导出的模块注册到实例对象 layui 上, 并标记模块已加载
var setApp = function (app, exports) {
layui[app] = exports; // layui 为实例对象, 在实例中添加自定义模块
config.status[app] = true; // 在congfig中设置模块状态
}
/**
* factory 工厂模式
* app 用户自定义导处模块名
* exports 用户自定义导处的数据
*/
typeof factory === 'function' && factory(function(app, exports) {
// 当前处于匿名函数内, 该匿名函数就是回调函数 exports
setApp(app, exports);
// 存储回调函数 (这里的匿名函数和 define 中 callback 一样), 用于后续如果重新执行模块
config.callback[app] = function(){
factory(setApp);
}
});
return this;
};
callback函数执行时,首先判断 factory 函数是否为函数,为函数时执行 factory 函数。
伪代码解释factory函数在实际代码中的位置
let factory = function(exports){
//do something
exports('demo', {
msg: 'Hello Demo'
});
};
layui.define(['layer', 'laypage', 'mod1'], factory);
exports函数在源码中为 factory 函数中的匿名函数参数。伪代码如下
let exports = function(app, exports) {
// 当前处于匿名函数内, 该匿名函数就是回调函数 exports
setApp(app, exports);
// 存储回调函数 (这里的匿名函数和 define 中 callback 一样), 用于后续如果重新执行模块
config.callback[app] = function(){
factory(setApp);
}
};
factory(exports);
exports函数中执行模块注册和存储回调函数,其中setApp函数通过 layui[app] = exports 语句把导出的内容挂在到全局中,并且使用 config.status[app] = true 语句表示该模块已经被加载。最后会向config中callback中注册函数,可用于以后某种场景调用。执行的内容或者结果和factory函数一样。
config 初始对象如下(在代码运行中还有向config中加入新属性的可能)
var config = {
modules: {}, // 记录模块物理路径
status: {}, // 记录模块加载状态
timeout: 10, // 符合规范的模块请求最长等待秒数
event: {} // 记录模块自定义事件
}
如有问题,欢迎指出