require.js的结构及常用组件用法

  require.js适用于包含多个js文件的复杂单页面应用。只要单个页面的js文件超过了一定的数量且相互间有依赖关系,并且项目中用到了模块化开发,就适合使用require.js。如果js文件不超过5个还是不必要使用require.js而直接引用就行。requireJs主要体现了一种模块化的编程思想,而你只需要按照requireJs的规范进行开发,就能将功能模块化,熟悉之后也能感受到模块化编程带来的好处:依赖清晰,模块分离,扩展维护方便,通过按需加载让页面加载更流畅。

本文转自:前端网原文
我无法将requireJs的API讲解的更好,这里我从requireJs在项目中的实际应用,我会从下面几点依次讲解和介绍:
  1. 1,目录结构
  2. 2,页面结构
  3. 3,配置requireJs
  4. 4,模块的加载
  5. 5,requireJs的模板组件(text.js)压缩组件(r.js)
  6. 6,mustache.js的和requireJs的组合应用

Require.js的目录结构:

     requireJs与普通的通过<script>标签直接引入的方式不同,它管理着所有js文件的引用依赖和加载,所以在页面上只需要通过一个<script>标签引入require.js的主文件,requireJs要求必须在这个标签上增加一个特殊的“data-main”属性。这个属性指定requireJs的配置文件,即指定大众组件(比如jquery.js,bootstrap.js,mustache.js)的路径并赋予moduleID(模块ID),然后初始化用户界面(比如动态渲染首页数据);moduleID是每个模块(每个js文件)对应路径的“缩写”,也就是说,requireJs用一个变量保存或者寻找相应文件模块的路径,需要使用时只需要使用该moduleID即对应变量,比如:待会儿的配置中“jqueryID”:"/thirdLib/jqueryJs/jquery.min",其中,前面的“jqueryID”是模块ID,后面则是jquery文件的路径,后面引用jquery的时候则只需要使用jqueryID便引用了jquery。在这种情况下,我们的目录结构应尽量扁平化(文件夹层级不要太深,所有js文件应放到同一个相对路径下,分类清晰。不止requireJs,所有类型的项目都应有一个简洁且分类明确的目录结构。)。

下面直接上结构图示例:

(每根红线连接至对应的介绍,可以看一下整个示例的结构及各个组件的大致功能。)

require.js


      可以看到,整个结构是按照:css ,html ,js ,index.html来分的,这样的好处是:相对于,index.html来说,每个文件都能直接向下寻找,不用“../../”这样有着复杂而多级的嵌套。所有js文件也能以“./js为根路径(baseUrl)”


Require.js的引入方式:

这是index.html中的具体代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>MAINFRAME</title>
    </head>
    <body>
        <h1>Hello RequireJs</h1>
        <div id="context"></div>
        <script type="text/javascript" src='./js/thirdLib/requirejs/require.js' data-main='./js/mainFrame.js' charset="utf-8"></script>
        // 使用require.js的应用只需在页面中引入require.js主体文件,并在该<script>标签中添加data-main属性并设置配置文件的路径,到这一步
       // 后面指定js文件路径时都可以忽略“.js”后缀了,因为requireJs默认会加上.js后缀,所以你再加一次的话会导致文件名不对,而无法加载。
    </body>
</html>


初始页面


Require.js的配置:
接着看一下mainFrame,js的代码,具体细节会在代码注释中详细讲解:

//定义一个require的配置方法,
var requireConfig={
    baseUrl: 'js/',  //这里指定requireJs加载js文件的根路径,它是相对于引用require.js的html页面来定的,
                          //比如我们现在的示例中是index.html引用了require.js,
                          //所以这个“js/”路径是相对于index.html的。
    paths  : {
        text:'thirdLib/requirejs/text',  //模板加载引擎,前面的“text”是moduleID,这里指定了路径,后面调用时只需用“text”这个ID,
        mustache:'thirdLib/mustache.min',  //模板渲染引擎,渲染html模板中并返回带内容的元素节点,再添加到页面中。
        jquery:'thirdLib/jqueryjs/jquery-2.1.4',  //jquery.js
        bootstrap:'thirdLib/jqueryjs/bootstrap.min',  //bootstrap.min.js
        backbone:'thirdLib/backbonejs/backbone',  //backboue.js
        underscore:'thirdLib/backbonejs/underscore'  //underscore
        //需要说明的是:这里所有的配置只是为一些常用组件指定moduleID,
        //书写的顺序不影响它们之间的倚赖关系。bootstrap写在jquery的前面也没有问题。
        //路径都需要忽略“.js”后缀,否则无法加载。
    },
    shim  : {  //配置js文件间的倚赖关系。
        bootstrap:{  //这里的模块ID 是上面paths配置中定义moduleID,我试了一下不论是否用引号包起来都有用。
            deps:['jquery'] //这里的意思是:bootstrap模块依赖jquery ,所以在要用到bootstrap时,
                                   //requireJs 会先将jquery加载进来才会执行bootstrap。
                                   //requireJs用这种方式来保证各个文件间的倚赖关系,并保证引用顺序。
        },
       backbone: {
            deps: ['underscore', 'jquery'],  //多个依赖关系以数组形式指定出来。
            exports: 'Backbone'  //加载完成后,用Backbone作为全局的模块ID(moduleID)
        },
    }
}

requirejs.config(requireConfig);  //这样看起来是不是和平时用的插件的调用方式差不多了呢。:)


define(function(require){  //定义一个模块,传入require对象。并执行函数。
    'use strict'

    require(['bootstrap'],function(){  //第一个参数传入函数内需要依赖的模块,因为在上面的shim配置中,已经指定了bootstrap倚赖于jquery,
                                                      //所以,这里调用bootstrap时,虽然没指定加载jquery,但requireJs依然会先将jquery加载进来。
                                                      //这就是指定js间依赖关系的好处。
        
       try{
            console.log('OK');  //输出==>'OK'
            console.log($);  //输出==>' function(selector, context)'
            //到这里这个模块已经能正常工作了,此时页面中加载了三个脚本:require.js , jquery.js ,bootstrap.js。
            //其它的模块还没开始使用,所以这里require也不会加载上面所有的js文件进来。这就是requireJs的按需加载。

        }catch(e){ , 
            console.error(e);
        }
    });

})


依照上面的配置,便通过requireJs的方法引入了jquery和bootstrap。但实际的模块化开发中,一个应用是有很多个模块的,那怎么新建一个自己的模块呢?


Mustache.js以及text.js组件的应用:
在上面的目录结构中,module文件夹放的是自己的功能模块。接下来我在mainContext.js中定义一个模块,在这个模块中初始化页面,并绑定事件。

先看一下模板文件的样子,好对下面的操作有个理解:
context.html:

<h1>这是第一个标题:{{{ first }}}</h1>
<h1>这是第二个标题:{{{ second }}}</h1>
<!--{{}}两个花括号不会解析html标签,{{{}}}三个花括号会解析html标签。
<div>
    这是一个按钮:{{{ btnTxt }}}
</div>


button.html:

<button id='btn_temp'>{{{ btnTempTxt }}}</button>

接下来是mainContext.js的代码:

define(function(require){  //定义一个模块,传入require对象。并执行函数。
    'use strict'
    
    var Mustache=require('mustache'),  //引入mustache,为后面模板渲染。
        Keyword=require('text!../../html/context.html'),  //用text.js引入模板文件,这里的格式是:“text.js的ID+!+模板路径“,
                                                                               //“text!../../html/context.html”中,"text"是mainFrame中定义的text.js的moduleID,并不是固定用“text”,
                                                                               //“!”用于分隔moduleID和路径,后面模板的路径是相对于当前文件的路径,这个就是相对于mainContext.js的
                                                                              //路径,具体可在上面的结构目录中对比一下。
        Tbutton=require('text!../../html/button.html');

    function MainContent(div){  //
        this._init(div);
        this._bindEvent();
        this.sayHello=function(){  //增加一个方法,后面测试用。
            alert('Hello!')
        }
    }

    MainContent.prototype._init = function (div) {  //扩展MainContent函数。传入一个需初始化的元素。

       var content = Mustache.render(Keyword, {  //这里是Mustache.js的用法,传入模板和渲染的数据。具体用法参考官方示例,
            first: 'RequireJs',
            second: 'Mustache',
            btnTxt: template(Tbutton, {   //我这里做了一个嵌套的渲染,即在一个模板中渲染另一个模板。通过下面的template()函数给Mustache换了个名字,
                                                        //以便区分。但实际是一样的。
                btnTempTxt: '嵌套的按钮'
            })
        });

        // var button = Mustache.render(Tbutton,{
        //     btnTxt : 'BIGBUTTON'
        // })

        div.html(content);  //通过jquery的html()方法将渲染出来的content添加进去。
    }

    MainContent.prototype._bindEvent=function(){  //给渲染的按钮添加点击事件,点击变换颜色。
        $('#btn_temp').on('click',function(){
            $(this).css('color','red')
        })
    }

    function template(temp,content){
        return Mustache.render(temp,content)
    }

    return MainContent;  //返回MainContent对象。
})

//平时要正常使用到这个MainContent对象一般是怎么做的呢?反正我是通过 "new"操作符来实例化该函数。
//这里我们将MainContent作为一个对象用return返回给了调用者。所以我们只需要考虑怎么加载到其它页面并调用。




模块的调用:
requireJs通过require()方法来调用一个模块:“require(moduleID)”;
回到之前的MainFrame.js中,我们在其中调用这个模块并初始化用户界面。因为config配置和上面的第二段中的不变,这里只贴出了mainFrame.js中的define模块的代码。

define(function(require){
    'use strict'
    var MainContext=require('module/mainContext');  //requireJs通过require(moduleID)方法调用一个模块,如果没有给模块指定moduleID
                                                                                 //则需要指出模块路径。这里通过require()方法,便引入了mainContext.js并将其中的
                                                                                //MainContent对象赋值给MainContext变量,后面操作MainContext和操作MainContent是一样的了。

    require(['bootstrap'],function(){
        try{
            console.log('OK');
            var div=$('#context');  //通过jquery选取主页上的需要初始化的区域。
            var frame = new MainContext(div);  //通过 “new” 操作符实例化MainContext对象,
            frame.sayHello(); //此处也能调用到MainContext对象的sayHello()方法;
        }catch(e){
            console.error(e);
        }
    });

})


通过上面的实例化,页面从便有了内容,还有了简单的点击事件:
页面初始化时渲染了页面并调用了sayHello()方法:

sayHello


页面初始化后的样子:

init

给按钮绑定了click事件:

click

下面给出示例里面的代码:

requirejs.config({
    //默认从 js/ 中加载模块
    baseUrl: 'js/',
    paths  : {
        text:'thirdLib/requirejs/text',
        mustache:'thirdLib/mustache.min',
        jquery:'thirdLib/jqueryjs/jquery-2.1.4',
        bootstrap:'thirdLib/jqueryjs/bootstrap.min'
    },
    shim  : {
        'bootstrap':{
            deps:['jquery']
        }
    }
});

define(function(require){
    'use strict'
    var MainContext=require('module/mainContext');
    var frame
    require(['bootstrap'],function(){
        try{
            console.log('OK');
            console.log($)
            var div=$('#context');
            frame = new MainContext(div);
            frame.sayHello()
        }catch(e){
            console.error(e);
        }
    });

})


mainContext.js的代码:

define(function (require) {
    'use strict'

    var Mustache = require('mustache'),
        Keyword = require('text!../../html/context.html'),
        Tbutton = require('text!../../html/button.html');

    function MainContent(div) {
        this._init(div);
        this._bindEvent();
        this.sayHello=function(){
            alert('Hello!')
        }
    }

    MainContent.prototype._init = function (div) {

        var content = Mustache.render(Keyword, {
            first: 'RequireJs',
            second: 'Mustache',
            btnTxt: template(Tbutton, {
                btnTempTxt: '嵌套的按钮'
            })
        });

        div.html(content);
    }

    MainContent.prototype._bindEvent=function(){
        $('#btn_temp').on('click',function(){
            $(this).css('color','red')
        })
    }

    function template(temp, content) {
        return Mustache.render(temp, content)
    }

    return MainContent;
})



到这里require的基本用法就是这样了,常规的项目使用已经足够使用,相信你在这样做出一个小的例子并运行通便能对requireJs有了初步的了解,并进行使用,熟悉了便可以尝试多做些实验,多增加几个模块相互引用,相信那样会更加理解其中的运行机制。还可以去浏览器中看一下define和require两个对象的区别和主要作用。这里就需要大家自己去尝试分析啦!

用r.js压缩代码:
最后介绍一下requireJs的 r.js,这是requireJs提供的一个配套压缩插件,但必须依赖node环境,要使用它压缩项目代码,请先安装nodeJs环境。
在压缩前,r.js也需要一个配置文件配置压缩路径以及各文件间的倚赖关系,如下:

({
    appDir:'./',//源目录
    baseUrl:'js',  //指定js文件基本路径。
    dir:'./build',//目标目录:将压缩的文件保存到 build文件夹,命名不限。
    paths  : {
        text:'thirdLib/requirejs/text',
        mustache:'thirdLib/mustache.min',
        jquery:'thirdLib/jqueryjs/jquery-2.1.4',
        bootstrap:'thirdLib/jqueryjs/bootstrap.min'
    },
    shim  : {
        bootstrap:{
            deps:['jquery']  //也需要指定倚赖关系。
        }
    },
    modules:[{
        name:'module/mainContext'  
    }],
    fileExclusingRegExp:/^(r|build)\.js$|^(.git)|^(.vscode)$/  //指定需要忽略的文件类型
})


接下来打开windows系统的 cmd或者Linux的terminal,:

(cd = 打开文件夹)cd  到项目的根目录:

require.js在项目中的结构及常用组件用法

cd_path


到了当前目录后 执行以下命令:

node ./js/thirdLib/requirejs/r.js -o build.js

之后nodeJs会执行压缩程序:

minify

如正常运行,就能看到build文件夹中有了和项目结构一样的文件,但已经被压缩过了。如不能成功压缩,请仔细检查执行路径,以及node环境是否安装正确。

以上便是我接触到的require整个结构和常用组件的一个介绍。希望能对看到的人有一定的帮助。同时如果有什么问题或不足,希望能指出来。我会及时修正。


阅读更多

扫码向博主提问

zh_rey

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • HTML
  • CSS
  • JavaScript
去开通我的Chat快问
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页