澳门新葡萄京官网注册 3

澳门新葡萄京官网注册JavaScript 模块化编程之加载器原理

实现一个自己的加载器

使用的方式:

//这个模块依赖的四个模块,加载器会分别去加载这四个模块;
define(["依赖0","依赖1","依赖2","依赖3"], function(依赖0,依赖1,依赖2,依赖3){

});

//返回一个空对象
define(function(){
    return {};
});

//直接把require当作是define来用就好了;
require(["依赖0","依赖1","依赖2","依赖3"], function(依赖0,依赖1,依赖2,依赖3) {
    //执行依赖0;
    依赖0(依赖1,依赖2,依赖3);
});

//这个加载器define函数和require函数的区别是,define我们可以传个name作为第一参数, 这个参数就是模块的名字, 好吧, 不管这些了.....;

以下为加载器的结构,因为代码量已经很少了, 所以每一函数都是必须的,
为了不影响全局, 把代码放在匿名自执行函数内部:

(function() {
    定义一个局部的difine;
    var define;
    //我偷偷加了个全局变量,好调试啊;
    window.modules = {
    };
    //通过一个名字获取绝对路径比如传"xx.js"会变成"http://www.mm.com/"+ baseUrl + "xx.html";
    var getUrl = function(src) {};
    //动态加载js的模块;
    var loadScript = function(src) {};
    //获取根路径的方法, 一般来说我们可以通过config.baseUrl配置这个路径;
    var getBasePath = function() {};
    //获取当前正在加载的script标签DOM节点;
    var getCurrentNode = function() {};
    //获取当前script标签的绝对src地址;
    var getCurrentPath = function() {};
    //加载define或者require中的依赖, 封装了loadScript方法;
    var loadDpt = function(module) {};
    //这个是主要模块, 完成了加载依赖, 检测依赖等比较重要的逻辑
    var checkDps = function() {};
    定义了define这个方法
    define = function(deps, fn, name) {};
    window.define = define;
    //require是封装了define的方法, 就是多传了一个参数而已;
    window.require = function() {
        //如果是require的话那么模块的名字就是一个不重复的名字,避免和define重名;
        window.define.apply([], Array.prototype.slice.call(arguments).concat( "module|"+setTimeout(function() {},0) ));
    };
});

加载器源码实现(兼容,chrome, FF, IE6 ==>>
IE11), IE11没有了readyState属性, 也没有currentScript属性,坑爹啊,
 无法获取当前正在执行的JS路径, 所以要用hack;

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
    (function() {
        var define;
        window.modules = {
        };
        var getUrl = function(src) {
            var scriptSrc = "";
            //判断URL是否是
            // ./或者
            // /或者
            // 直接是以字符串开头
            // 或者是以http://开头;
            if( src.indexOf("/") === 0 || src.indexOf("./") === 0 ) {
                scriptSrc = require.config.base + src.replace(/^//,"").replace(/^.//,"");
            }else if( src.indexOf("http:") === 0 ) {
                scriptSrc = src;
            }else if( src.match(/^[a-zA-Z1-9]/) ){
                scriptSrc = require.config.base + src;
            }else if(true) {
                alert("src错误!");
            };
            if (scriptSrc.lastIndexOf(".js") === -1) {
                scriptSrc += ".js";
            };
            return scriptSrc;
        };

        var loadScript = function(src) {
            var scriptSrc = getUrl(src);
            var sc = document.createElement("script");
            var head = document.getElementsByTagName("head")[0];
            sc.src = scriptSrc;
            sc.onload = function() {
                console.log("script tag is load, the url is : " + src);
            };
            head.appendChild( sc );
        };

        var getBasePath = function() {
            var src = getCurrentPath();
            var index = src.lastIndexOf("/");
            return  src.substring(0,index+1);
        };

        var getCurrentNode = function() {
            if(document.currentScript) return document.currentScript;
            var arrScript = document.getElementsByTagName("script");
            var len = arrScript.length;
            for(var i= 0; i<len; i++) {
                if(arrScript[i].readyState === "interactive") {
                    return arrScript[i];
                };
            };

            //IE11的特殊处理;
            var path = getCurrentPath();
            for(var i= 0; i<len; i++) {
                if(path.indexOf(arrScript[i].src)!==-1) {
                    return arrScript[i];
                };
            };
            throw new Error("getCurrentNode error");
        };

        var getCurrentPath = function() {
            var repStr = function(str) {
                return (str || "").replace(/[&?]{1}[wW]+/g,"") || "";
            };
            if(document.currentScript) return repStr(document.currentScript.src);

            //IE11没有了readyState属性, 也没有currentScript属性;
            // 参考 https://github.com/samyk/jiagra/blob/master/jiagra.js
            var stack
            try {
                a.b.c() //强制报错,以便捕获e.stack
            } catch (e) { //safari的错误对象只有line,sourceId,sourceURL
                stack = e.stack
                if (!stack && window.opera) {
                    //opera 9没有e.stack,但有e.Backtrace,但不能直接取得,需要对e对象转字符串进行抽取
                    stack = (String(e).match(/of linked script S+/g) || []).join(" ")
                }
            }
            if (stack) {
                /**e.stack最后一行在所有支持的浏览器大致如下:
                 *chrome23:
                 * at http://113.93.50.63/data.js:4:1
                 *firefox17:
                 *@http://113.93.50.63/query.js:4
                 *opera12:http://www.oldapps.com/opera.php?system=Windows_XP
                 *@http://113.93.50.63/data.js:4
                 *IE10:
                 *  at Global code (http://113.93.50.63/data.js:4:1)
                 *  //firefox4+ 可以用document.currentScript
                 */
                stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分
                stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/s/, "") //去掉换行符
                return stack.replace(/(:d+)?:d+$/i, "") //去掉行号与或许存在的出错字符起始位置
            };

            //实在不行了就走这里;
            var node = getCurrentNode();
            //IE>=8的直接通过src可以获取,IE67要通过getAttriubte获取src;
            return repStr(document.querySelector ? node.src : node.getAttribute("src", 4)) || "";

            throw new Error("getCurrentPath error!");
        };

        var loadDpt = function(module) {
            var dp = "";
            for(var p =0; p<module.dps.length; p++) {
                //获取绝对的地址;
                var dp = getUrl(module.dps[p]);
                //如果依赖没有加载就直接加载;
                if( !modules[dp] ) {
                    loadScript(dp);
                };
            };
        };

        //主要的模块, 检测所有未加载的模块中未完成了的依赖是否加载完毕,如果加载完毕就加载模块, 如果加载过的话,而且所有依赖的模块加载完毕就执行该模块
        //而且此模块的exports为该模块的执行结果;
        var checkDps = function() {
            for(var key in modules ) {
                //初始化该模块需要的参数;
                var params = [];
                var module = modules[key];
                //加载完毕就什么都不做;
                if( module.state === "complete" ) {
                    continue;
                };
                if( module.state === "initial" ) {
                    //如果依赖没有加载就加载依赖并且modules没有该module就加载这个模块;
                    loadDpt(module);
                    module.state = "loading";
                };
                if( module.state === "loading") {
                    //如果这个依赖加载完毕
                    for(var p =0; p<module.dps.length; p++) {
                        //获取绝对的地址;
                        var dp = getUrl(module.dps[p]);
                        //如果依赖加载完成了, 而且状态为complete;;
                        if( modules[dp] && modules[dp].state === "complete") {
                            params.push( modules[dp].exports );
                        };
                    };
                    //如果依赖全部加载完毕,就执行;
                    if( module.dps.length === params.length ) {
                        if(typeof module.exports === "function"){
                            module.exports = module.exports.apply(modules,params);
                            module.state = "complete";
                            //每一次有一个模块加载完毕就重新检测modules,看看是否有未加载完毕的模块需要加载;
                            checkDps();
                        };
                    };
                };
            };
        };

        //[],fn; fn
        define = function(deps, fn, name) {
            if(typeof deps === "function") {
                fn = deps;
                deps = [];//我们要把数组清空;
            };

            if( typeof deps !== "object" && typeof fn !== "function") {
                alert("参数错误")
            };

            var src = getCurrentPath();
            //没有依赖, 没有加载该模块就新建一个该模块;
            if( deps.length===0 ) {
                modules[ src ] = {
                    name : name || src,
                    src : src,
                    dps : [],
                    exports : (typeof fn === "function")&&fn(),
                    state : "complete"
                };
                return checkDps();
            }else{
                modules[ src ] = {
                    name : name || src,
                    src : src,
                    dps : deps,
                    exports : fn,
                    state : "initial"
                };
                return checkDps();
            }
        };

        window.define = define;
        window.require = function() {
            //如果是require的话那么模块的名字就是一个不重复的名字,避免和define重名;
            window.define.apply([], Array.prototype.slice.call(arguments).concat( "module|"+setTimeout(function() {},0) ));
        };
        require.config = {
            base : getBasePath()
        };
        require.loadScript = loadScript;
        var loadDefaultJS = getCurrentNode().getAttribute("data-main");
        loadDefaultJS && loadScript(loadDefaultJS);
    })();
    </script>
</head>
<body>
</body>
</html>

从叶大大那边偷的一个加载器,
这个加载器有点像jQuery中延迟对象($.Deferred)有关的方法when($.when)的实现;

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        (function () {

            //存储已经加载好的模块
            var moduleCache = {};

            var define = function (deps, callback) {
                var params = [];
                var depCount = 0;
                var i, len, isEmpty = false, modName;

                //获取当前正在执行的js代码段,这个在onLoad事件之前执行
                modName = document.currentScript && document.currentScript.id || 'REQUIRE_MAIN';

                //简单实现,这里未做参数检查,只考虑数组的情况
                if (deps.length) {
                    for (i = 0, len = deps.length; i < len; i++) {
                        (function (i) {
                            //依赖加一
                            depCount++;
                            //这块回调很关键
                            loadMod(deps[i], function (param) {
                                params[i] = param;
                                depCount--;
                                if (depCount == 0) {
                                    saveModule(modName, params, callback);
                                }
                            });
                        })(i);
                    }
                } else {
                    isEmpty = true;
                }

                if (isEmpty) {
                    setTimeout(function () {
                        saveModule(modName, null, callback);
                    }, 0);
                }

            };

            //考虑最简单逻辑即可
            var _getPathUrl = function (modName) {
                var url = modName;
                //不严谨
                if (url.indexOf('.js') == -1) url = url + '.js';
                return url;
            };

            //模块加载
            var loadMod = function (modName, callback) {
                var url = _getPathUrl(modName), fs, mod;

                //如果该模块已经被加载
                if (moduleCache[modName]) {
                    mod = moduleCache[modName];
                    if (mod.status == 'loaded') {
                        setTimeout(callback(this.params), 0);
                    } else {
                        //如果未到加载状态直接往onLoad插入值,在依赖项加载好后会解除依赖
                        mod.onload.push(callback);
                    }
                } else {

                    /*
                     这里重点说一下Module对象
                     status代表模块状态
                     onLoad事实上对应requireJS的事件回调,该模块被引用多少次变化执行多少次回调,通知被依赖项解除依赖
                     */
                    mod = moduleCache[modName] = {
                        modName: modName,
                        status: 'loading',
                        export: null,
                        onload: [callback]
                    };

                    _script = document.createElement('script');
                    _script.id = modName;
                    _script.type = 'text/javascript';
                    _script.charset = 'utf-8';
                    _script.async = true;
                    _script.src = url;

                    //这段代码在这个场景中意义不大,注释了
                    //      _script.onload = function (e) {};

                    fs = document.getElementsByTagName('script')[0];
                    fs.parentNode.insertBefore(_script, fs);

                }
            };

            var saveModule = function (modName, params, callback) {
                var mod, fn;

                if (moduleCache.hasOwnProperty(modName)) {
                    mod = moduleCache[modName];
                    mod.status = 'loaded';
                    //输出项
                    mod.export = callback ? callback(params) : null;

                    //解除父类依赖,这里事实上使用事件监听较好
                    while (fn = mod.onload.shift()) {
                        fn(mod.export);
                    }
                } else {
                    callback && callback.apply(window, params);
                }
            };

            window.require = define;
            window.define = define;

        })();
    </script>
</head>
<body>
</body>
</html>

CMD

  在Sea.js中,所有JavaScript模块都遵循CMD(Common
Module
Definition)模块定义规范。该规范明确了模块的基本书写格式和基本交互规则

  AMD规范简单到只有一个API,即define函数

define([module-name?], [array-of-dependencies?], [module-factory-or-object]);

  module-name: 模块标识,可以省略

  array-of-dependencies: 所依赖的模块,可以省略

  module-factory-or-object: 模块的实现,或者一个JavaScript对象

  CMD规范也与之类似,只不过第三个参数factory的实现方式不同。在CMD规范中,一个模块就是一个文件。代码的书写格式如下

define(id?, deps?, factory)

  与AMD规范类似,define是一个全局函数,用来定义模块。字符串 id 表示模块标识,数组 deps 是模块依赖。这两个参数可以省略,通常由构建工具自动生成

  通常地,define()方法的第三个参数factory是一个函数,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:requireexports 和 module

  [注意]factory()方法的参数如果不需要,可以省略,但不可以修改,如修改为’a’、’b’、’c’,也不可以改变其参数的顺序。在函数内部,也不能对参数名重新赋值,如’var
a = require; ‘

define(function(require, exports, module) {

  // 模块代码

});

【require】

require 是 factory澳门新葡萄京官网注册 , 函数的第一个参数。require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口。通俗地说,通过require()方法来调用其他模块的属性或方法

define(function(require, exports, module) {

  // 获取模块 a 的接口
  var a = require('./a');

  // 调用模块 a 的方法
  a.doSomething();

});

  这个require()方法的实现和功能都特别类似于CommonJS中的require()方法。或许,有人会有疑惑,require()不是一个同步方法吗?在CommonJS中是的,在seaJS中也可以这么说,但并不完整。更合理的说法应该是,模块内的同步加载,实际表现为对模块a进行预下载

  例如下面的代码,即使不点击页面,a.js也会预先下载。点击页面后,控制台依次输出’a’和’a.test’

// main.js
define(function(require, exports, module){
    document.onclick = function(){
        var a = require('js/a');
        a.test();
    }    
});
define(function(require, exports, module){
    console.log('a');
    exports.test = function(){
        console.log('a.test');
    }
})

  能不能执行时再下载呢?类似于懒加载。有的,使用require.async()方法。require.async 方法用来在模块内部异步加载模块,并在加载完成后执行指定回调

// main.js
define(function(require, exports, module){
    document.onclick = function(){
        require.async('./a',function(a){
            a.test();
        });
    }    
});
//a.js
define(function(require, exports, module){
    console.log('a');
    exports.test = function(){
        console.log('a.test');
    }
})

【exports】

exports 是一个对象,用来向外提供模块接口。与CommonJS的exports功能类似

define(function(require, exports) {

  // 对外提供 foo 属性
  exports.foo = 'bar';

  // 对外提供 doSomething 方法
  exports.doSomething = function() {};

});

  除了给 exports 对象增加成员,还可以使用 return 直接向外提供接口,这种方式与requireJS的方式类似

define(function(require) {

  // 通过 return 直接提供接口
  return {
    foo: 'bar',
    doSomething: function() {}
  };

});

  如果 return 语句是模块中的唯一代码,还可简化为

define({
  foo: 'bar',
  doSomething: function() {}
});

【module】

  module 是一个对象,上面存储了与当前模块相关联的一些属性和方法

// main.js
define(['./a'],function(require, exports, module){
    console.log(module);
})

澳门新葡萄京官网注册 1

  module.uri表示根据模块系统的路径解析规则得到的模块绝对路径

  module.id是模块的唯一标识,一般情况下没有在define中手写id参数时,module.id的值就是module.uri,两者完全相同

  module.dependencies是一个数组,表示当前模块的依赖

  module.exports是当前模块对外提供的接口。传给factory构造方法的exports参数是module.exports对象的一个引用。只通过exports参数来提供接口,有时无法满足开发者的所有需求。
比如当模块的接口是某个类的实例时,需要通过module.exports来实现

  [注意]对module.exports的赋值需要同步执行,不能放在回调函数里。下面这样是不行的

define(function(require, exports, module) {
  // 错误用法
  setTimeout(function() {
    module.exports = { a: "hello" };
  }, 0);
});

 

世面上有好多JavaScript的加载器,比如 sea.js, require.js, yui loader,
labJs…., 加载器的使用范围是一些比较大的项目,
个人感觉如果是小项目的话可以不用,  我用过seaJS和requireJS,
在项目中用过requireJS, requireJS是符合AMD,全称是(Asynchronous Module
Definition)即异步模块加载机制 , seaJS是符合CMD规范的加载器。

最后

  CommonJS、requireJS、seaJS这三种模块化方案,并没有高低之分。随着各个方案的不断升级,语言方面相互借鉴,使用差异逐渐变小。以上三种库级别的模块化方案,需要引入额外的库,且所遵循的规范并不是标准组织制定的,权威性不足

  随着ES6在语言层面上开始支持模块化,ES6的模块化写法才是未来的模块化标准

一个例子

写一个MVC的小例子,代码简单, 高手无视,  目录结构如下:

澳门新葡萄京官网注册 2

我们把所有的事件放到了controller/mainController.js里面,

define(["model/data","view/view0"],function(data, view) {
    var init = function() {
        var body = document.getElementsByTagName("body")[0];
        var aBtn = document.getElementsByTagName("button");
        for(var i=0; i< aBtn.length; i++) {
            aBtn[i].onclick = (function(i) {
                return function() {
                    body.appendChild( view.getView(data[i]) );
                };
            })(i);
        };
    };
    return {
        init : init
    };
});

把所有的数据放到了model/data.js里面;

define(function() {
    return [
        {name : "qihao"},
        {name : "nono"},
        {name : "hehe"},
        {name : "gege"}
    ];
})

视图的JS放到了view的目录下,view0.js主要负责生成HTML字符串或者DOM节点;

define(function() {
    return {
        getView : function(data) {
            var frag = document.createDocumentFragment();
                frag.appendChild( document.createTextNode( data.name + " ") );
            return frag;
        }
    }
});

入口是app.js,他和load.html是同级目录:

require(["controller/mainController"],function( controller ) {
    controller.init();
});

load.html这个是主界面:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title></head>
<body>
<button>0</button>
<button>1</button>
<button>2</button>
<button>3</button>
<script src="require.js" data-main="app.js"></script>
</body>
</html>

例子的源码下载地址: 下载

配置

【路径】

  如果不配置路径,在requireJS中,默认路径是data-main的所处目录,比如data-main=’js/main’,则所处路径是’js’目录下

  而seaJS则不同,它的默认路径是seaJS文件的所处目录,比如seaJS文件所处路径是’demo’目录下,进行如下入口设置后

seajs.use('js/main');

  说明main.js的目录为’demo/js/main.js’。如果main.js依赖于a.js,且a.js与main.js处于同一目录下,则以下两种写法都正确

  1、’demo’ + ‘js/a’ = ‘demo/js/a.js’

// main.js
define(['js/a'],function(require, exports, module){

})

  2、’./’表示当前目录,即’demo/js’,所以 ‘./a’ = ‘demo/js/a.js’

// main.js
define(['./a'],function(require, exports, module){

})

  在requireJS中使用baseUrl来配置基础路径,而在seaJS中使用base。进行如下配置后,真实路径为
‘demo’ + ‘js’ + ‘main’ = ‘demo/js/main.js’

<script src="sea.js"></script>
<script>
    seajs.config({
        base: 'js'
    });
    seajs.use("main");
</script>

【别名】

  当模块标识很长时,可以使用 alias 来简化

seajs.config({
  alias: {
    'jquery': 'jquery/jquery/1.10.1/jquery',
    'app/biz': 'http://path/to/app/biz.js',
  }
});

【目录】

  当目录比较深,或需要跨目录调用模块时,可以使用 paths 来简化书写

seajs.config({
  paths: {
    'gallery': 'https://a.alipayobjects.com/gallery',
    'app': 'path/to/app',
  }
});

 

AMD__和__CMD

AMD规范是依赖前置, CMD规范是依赖后置, AMD规范的加载器会把所有的JS中的依赖前置执行。 CMD是懒加载,
如果JS需要这个模块就加载, 否则就不加载,
导致的问题是符合AMD规范的加载器(requireJS),
可能第一次加载的时间会比较久, 因为他把所有依赖的JS全部一次性下载下来;

常识,jQuery是支持AMD规范,并不支持CMD规范,也就是说,
如果引入的是seaJS,想要使用jQuery,要用alias配置,
或者直接把  直接引入页面中;

//这是jQuery源码的最后几行, jQuery到了1.7才支持模块化;
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
if ( typeof define === "function" && define.amd ) {
    define( "jquery", [], function() {
        return jQuery;
    });
};

与AMD区别

  AMD 是 RequireJS 在推广过程中对模块定义的规范化产出,CMD 是 SeaJS
在推广过程中对模块定义的规范化产出。这些规范的实现都能达成浏览器端模块化开发的目的

  AMD与CMD主要有以下两点区别

  1、所依赖模块的执行时机

  对于依赖的模块,AMD是提前执行,CMD是延迟执行

  AMD在加载模块完成后就会执行该模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行。不过,新版本的RequireJS也可以延迟执行

  CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。如果使用require.async()方法,可以实现模块的懒加载,即不执行不下载

  2、CMD推崇依赖就近,AMD推崇依赖前置

// CMD
define(function(require, exports, module) { 
    var a = require('./a')
     a.doSomething()  
    // 此处略去 100 行   
    var b = require('./b') // 依赖可以就近书写  
    b.doSomething()   
    // ... 
})

// AMD
define(['./a', './b'], function(a, b) {  // 依赖必须一开始就写好
    a.doSomething()    
    // 此处略去 100 行    
    b.doSomething()    
    ...
})

  当然,AMD也支持CMD的写法,同时还支持将require作为依赖项传递

 

使用方法

比如我们可以这样定义一个模块:

//文件所在的路径地址为:http://localhost:63342/module/script/dir2/1.js
define(function() {
    return "!!!!";
});

也可以这样定义一个模块:

//这个文件的路径为http://localhost:63342/module/main.js ,而且有一个依赖, 加载器会自动去加载这个依赖, 当依赖加载完毕以后, 会把这个依赖(就是script/dir2/1.js)执行的返回值作为这个函数的参数传进去;
require(["script/dir2/1.js"], function(module1) {
    console.log(module1);
});
//实际上会打印出 "!!!!"

一般来说,一个模块只能写一个define函数,
define函数的传参主要有两种方式:

1:正常上可以是一个函数;

2:可以是一个数组类型依赖的列表, 和一个函数;

如果一个模块写了多个define会导致模块失灵,
先定义的模块被后定义的模块给覆盖了 ( 当然了, 一般我们不那样玩);

一个模块内可以写多个require, 我们可以直接理解require为匿名的define模块,
一个define模块内可以有多个require, 而且require过的模块会被缓存起来,
这个缓存的变量一般是在闭包内,
而且名字多数叫modules什么的…..;

我们通过加载器开发实现的模块化开发要遵守一种规范,
规范了一个模块为一个JS,那么我们就可以新建几个目录为conroller,view,
model, 也是为了后期更好的维护和解耦:

澳门新葡萄京官网注册 3

入口

  requireJS通过data-main来设置入口,而seaJS则通过sea.use()来设置。sea.js
在下载完成后,会自动加载入口模块

seajs.use(id, callback?)

  [注意]callback参数可选,省略时,表示无需回调

<script src="sea.js"></script>
<script>
  seajs.use('js/main');
</script>

  加载单个依赖,运行以下代码后,控制台输出’test’

//index.html
<script src="sea.js"></script>
<script>
    seajs.config({
        base: 'js'
    });
    seajs.use("main",function(a){
        a.test();
    });
</script>

// main.js
define(['./a'],function(require, exports, module){
    return {
        test : function(){
            console.log('test');
        }
    }
})

  加载多个依赖

//并发加载模块 a 和模块 b,并在都加载完成时,执行指定回调
seajs.use(['./a', './b'], function(a, b) {
  a.init();
  b.init();
});

【DOMReady】

seajs.useDOM ready事件没有任何关系。如果某些操作要确保在DOM ready后执行,需要使用jquery等类库来保证

seajs.use(['jquery', './main'], function($, main) {
  $(document).ready(function() {
    main.init();
  });
});

【打包】

  引入 sea.js 时,可以把 sea.js 与其他文件打包在一起,可提前合并好,或利用
combo
服务动态合并。无论哪一种方式,为了让 sea.js 内部能快速获取到自身路径,推荐手动加上 id 属性

<script src="path/to/sea.js" id="seajsnode"></script>

  加上 seajsnode 值,可以让 sea.js 直接获取到自身路径,而不需要通过其他机制去自动获取。这对性能和稳定性会有一定提升,推荐默认都加上

 

前面的话

  CMD(Common Module Definition)表示通用模块定义,该规范是国内发展出来的,由阿里的玉伯提出。就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS和requireJS一样,都是javascript的模块化解决方案。本文将详细介绍CMD和seaJS

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注