Layui源码解读之define函数

一、layui.define 用法

layui.define([mods], callback)

通过layui.define该方法可在新的 JS 文件中定义一个 layui 模块。

  1. mods 是可选的,用于声明该模块所依赖的模块。
  2. 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 函数。
Layui源码解读之define函数_第1张图片

伪代码解释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: {} // 记录模块自定义事件
}

如有问题,欢迎指出

你可能感兴趣的:(js,layui,layui,数学建模,前端)