• requireJS


    参考:http://www.ruanyifeng.com/blog/2012/11/require_js.html

    什么是模块化?

    以前我们可能会这样做代码分工 
    //modules.js -----
    var moduleA = {......}
    var moduleB = {......}
    var moduleC = {......}

    然后每个页面都引入JS

    <script src="modules.js"></script>

    不管这个页面用到了几个模块,你都要把整个文件加载进来,于是我们就想,不如分开吧
    然后我们的代码变成了这样:
    //moduleA.js -----
         var moduleA = {......}
    //moduleB.js -----
         var moduleB = {......}
    //moduleC.js -----
         var moduleC = {......}

    但是,由于各个模块之间存在相互引用的依赖关系,所以我们这样引入JS:
    <script src="jquery.js"></script>
    <script src="moduleB.js"></script>
    <script src="moduleC.js"></script>
    <script src="moduleA.js"></script>
    假设A引用了C,而C引用了B,ABC里面都用到了JQ这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的moduleC.js要在moduleA.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

    于是require.js出现了,就是为了解决这两个问题:
            (1)实现js文件的异步加载,避免网页失去响应;
      (2)管理模块之间的依赖性,便于代码的编写和维护。

    按照requireJS当中的规范要求,你只需加载一个文件就可以,但同时需要带上一个配置文件config.js

    第一步:
    	<script data-main ="main.js" src ="require.js"  >
    	/**	浏览器会先加载完require.js后,再加载main.js
    		*加载这个文件,也可能造成网页失去响应。解决办法有两个,
    		*一个是把它放在网页底部加载,另一个是写成下面这样:*/
    	</script>
    	<!--或-->
    	<script data-main ="main.js" src ="require.js" defer async="true" >
    	/*async属性表明这个文件需要异步加载,避免网页失去响应。
    	 * IE不支持这个属性,只支持defer,所以把defer也写上。*/
    	</script>
    这个require.js你可以从官网下载,这个main.js必须自己完成。不用担心,它写起来非常简单:
    在这之前我们需要先定义一个config.js用来配置将会用到的js文件:
    		requirejs.config({
    			baseUrl: "js",//baseUrl所有的路径的"基目录"
    			paths: {
    				//模块名称:文件路径,注意文件没有后缀名,因为在require看来所有的模块都是JS
    				"jquery": "jquery.1.11.3"
    			}
    		});

    紧接着,我们可以定义自己的模块文件了,main.js

    首先main.js也是一个模块,但是我们必须对这个JS改造一下,让它符合require的规范(AMD)要求,才能使用
    		define(["jquery"],function(jq){
    		    //根据我们之前的设定,模块main需要使用Jquery
    		    //define函数中的第一个参数,用来表明,我们即将引用哪个模块。
    		    //由于之前我们已经定义过了jquery模块,所以这里可以直接使用
    		    //注意,你如果不写声明,这里是用不了jQuery的
    		    //你如果注意到第一个参数是一个数组,那就应该猜到,其实我们可以一次引用好多模块
    		    //jq变量就是jquery,你如果不习惯,把名字改回$就是了
    		
    		    return {
    		        start: function(){
    		             jq("#box").show(1000);
    		             console.log("模块main提供的start方法");
    		             //为什么这里要return呢? 因为我们定义的模块要被其他人使用
    		             //那又为什么要return对象呢?为了更符合模块化思维以及面相对象的原则
    		             //我们返回一个对象而不是函数,使用起来会更方便(待会讲完怎么调用你就知道了)
    		        }
    		    }
    		});

    好了,模块main定义完了,我们可以来试试。当然,用之前别忘了修改配置config.js
    		requirejs.config({
    			baseUrl: "js",//baseUrl所有的路径的"基目录"
    			paths: {
    				//模块名称:文件路径,注意文件没有后缀名,因为在require看来所有的模块都是JS
    				"jquery": "jquery.1.11.3",
    				"main":"main.js"
    				//注意:配置路径时,排名不分先后,顺序可以任意。
    			}
    		});

    我们有一个index.html页面,包含一个main.js文件。
    		/* config是config.js相对于main.js的位置,默认为根目录
                          只有先引用config,才能引用配置好的所有模块*/
    	  require(["config"],function(){
              require(["jquery","main"],function($,ma){
                   //我们引用两个模块jquery、main
                   ma.start(); //ma就是我们刚才在模块ma中返回的对象
              })
         })
    当然,因为前边我们定义了main是依赖于jquery的(define(["jquery"],function(){})),因此也可以只加载main:
    	  require(["config"],function(){
              require(["main"],function($,ma){
              	/**
              	 * main依赖于jquery,require会自动帮我们加载jquery
                * 但在加载后在控制台直接使用$或jQuery也是好使的,
                * 這是因为jquery已经加载过了,而且jQuery是绑定在window上的
              	*/
                ma.start(); 
              })
         })
    
    根据我们一开始的设定(A引用了C,而C引用了B,ABC里面都用到了JQ )
    和上面的讲解,你能否自己完成moduleC.js和moduleA.js?
    //moduleC.js -----
         define(["moduleb","jquery"],function(mb,$){
              return {
                  .......
              }
         });
    
    //moduleA.js -----
         define(["modulec","jquery"],function(mc,$){
              return {
                  .......
              }
         });



    别忘了配置:
    //config.js 
         paths: {
             "jquery": "jquery/jquery.1.11.3",
             "modulea" : "ms/moduleA",
             "moduleb" : "ms/moduleB",
             "modulec" : "ms/moduleC"
         }

    一些问题:

    问:加载配置文件的路径问题?

    根据你目前的页面的业务JS文件的位置来决定,也就是说,负责加载config的JS在哪里,路径就从哪里开始

    例如index.js在根目录,config也在根目录:
    require(["config"],function(){...});

    例如index.js在js目录中,config在根目录
    require(["../oncfig"], function(){...});

    例如index.js在根目录中,config在js目录
    require(["js/config", function(){...}];

    问:是不是所有要加载的模块,都必须写define函数,为什么jquery就没写,一样可以加载?

    谁说JQ没写呢?这是jquery的部分源代码。
    if ( typeof define === "function" && define.amd ) {
         define( "jquery", [], function() {
              return jQuery;
         });
    }

    所以,所有的JS都必须遵循require的规范,才能够正确的加载


    问:我自己写了一大堆的工具函数,请问怎么加载?

    首先,工具函数也可以用对象来表示
    //common.js -----
         define(function(){
              return {
                   getStyle : function(){ ........ },
                   randomColor : function(){ ......... }         
              }  
         });

    当然如果你比较任性,非要写成这个样子:
    //common.js -----
         function getStyle(){ ......... }
         function randomColor(){ ........ }




    解决办法也是有的:
    请百度requireJS, shim配置

    问:有一些插件,本身没有导出任何对象或核心函数,只是对某个框架的扩展,例如 my.jquery.scroll.js 该怎么用?

    官方文档给出的答案是使用shim配置
    //config.js -----
         require.config({
               baseUrl: "js",
               paths: {
                     "jquery" :  "jquery.1.11.3",
                     "jquery.scroll" : "my.jquery.scroll"
               },
               shim: {
                     "jquery.scroll": {
                            deps: ["jquery"],
                            exports: "jQuery.fn.scroll"
                     }
               }     
         });


    这是第一种方式, deps表示它依赖了哪个模块,exports表示它输出哪个函数,函数名字要和插件代码里保持一致
    使用方式:
    //index.js -----
         require(["config"],function(){
              require(["jquery","jquery.scroll"],function($){
                    $("#box").scroll(500);
              })
         })

    第二种配置方式:
    //config.js -----
         require.config({
               baseUrl: "js",
               paths: {
                     "jquery" :  "jquery.1.11.3",
                     "jquery.scroll" : "my.jquery.scroll"
               },
               shim: {
                     "jquery.scroll":  ["jquery"]
               }     
         });
    


    使用方法同上

    But! 官方文档又说,这样使用可能导致错误! 请参考原文:


    所以,终极解决方案是,把插件改成define调用.........

    问:如果我用到了两个框架,Jquery和Zepto,他们的核心函数都叫$ ,那该怎么办呢?

    require(["jquery","zepto"],function(jq,zepto){
         // 改个名字就不冲突了
    })
    问:jQuery插件使用requireJs
    		//传入jQuery是因为在require->define([],function(){
    		//       内是另一个作用域
    		//  })
    		//无法直接通过jQuery直接访问,当然也可以使用window.jQuery
    		define(["jquery"], function(jQuery) {//适配器模式
    			//这里不需要返回值,因为本身就是对jQuery的扩展,使用时直接在jquery对象上调用即可
    			(function($,undefined){
    				$.fn.extend({
    					
    				})
    			})(jQuery);
    		});


    说一说好处:

    讲了这么多,requirejs所倡导的模块化开发,好处在哪里呢?

    1 你有没有发现,整个项目当中,再也没有出现一个全局变量?
    2 你有没有发现,你再也没有考虑过加载顺序的问题?
    3 你有没有发现,即使两个框架名字冲突了也没关系?
    4 而且你肯定没有发现,所有的JS文件的加载过程,已经变成了异步。
    5 最后,你还发现,用了requireJS,你的代码想不写成面相对象都难??


    关于AMD和CMD

    总在网上看大家讨论AMD和CMD,到底是什么东西呢?
    AMD就是require所倡导的模块化开发的方式

    还有一个叫CommonJS的,不过还是和requireJS有些区别,主要针对NODE后端开发

    另外还有一个大名鼎鼎的SeaJS,作者是淘宝的玉伯,于是诞生了CMD规范
    根据作者自己的介绍,SeaJS各方面都比requireJS强大
    这个就不做评价了

    至于区别呢?

    AMD推崇的是依赖前置:
    define(["a","b","c"],function(a,b,c){ //我们把所有依赖提前写好了
         a.doSomething (); //这里直接使用
          b.doSometing();
    })

    CMD推崇的是依赖就近:
    define(function(require, exports, module) {
         var a = require('./a');
         a.doSomething();
         .........
         var b = require('./b') // 依赖可以就近书写,用到的时候再加载
         b.doSomething()
    })

    当然requireJS也支持CMD的写法,不过作者本人是不推荐这么写的





  • 相关阅读:
    房子不是盖来住的
    房子不是盖来住的
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/fanlinqiang/p/7741211.html
Copyright © 2020-2023  润新知