资讯专栏INFORMATION COLUMN

Require.js实现js模块化管理教程

fox_soyoung / 405人阅读

摘要:再者,引入一大堆的文件也不美观,而使用即可实现的模块化异步加载。通过定义模块的方式可分为以下两类。当和这两个模块加载完成之后将会执行回调函数。插件可以使回调函数在结构加载完成之后再执行。最好的方式是使用字符串但这很难管理尤其实在多行的时候。

什么是Require.js

Require.js是一个AMD规范的轻量级js模块化管理框架,最新版本require.js 2.1.11压缩后只有14.88K,它可以把js代码分成一个个模块,实现异步或动态加载,还能很清晰的看出模块之间的依赖,从而提高代码质量,性能和可维护性。Require.js的作者是AMD规范的创始人 James Burke。

Require.js能带来什么好处

下面我们可以举一个简单的例子说明:

通常我们的页面结构是以下这样




   
   require
   
   
   
   
   
   
   


require

a.js里面的代码

alert("require");

当运行页面可以发现当弹出alert时需要点击确定才会显示div的内容,因为页面的js是同步渲染,js的渲染必然会阻塞后面的html渲染。再者,引入一大堆的js文件也不美观,而使用require.js即可实现js的模块化异步加载。

如何使用Require.js

先到require.js官网下载最新版本,然后引入到页面,如下:

data-main属性不能忽略,data-main指向的文件是主代码所在的文件,main.js里面配置的脚本都将是异步加载,main.js所在的目录默认为根路径。

require.js config

config方法用于配置运行参数。首先设置参数,看下面的例子:
我的项目文件结构如下

主文件main.js

require.config({
    baseUrl: "js",
    paths: {
        "jquery": ["lib/jquery-1.8.3.min"],
        "popup": ["lib/popup"],
        "moduleA": ["app/moduleA"],
        "moduleB": ["appmoduleB"]
    },
    shim: {
        "popup": {
            deps: ["jquery"]
        }
    }
});

config方法接收一个对象参数,以下解释各属性作用。
baseUrl:设置根路径,如没有设置该属性则默认为主文件所在的目录,这里设置JS目录为根路径。
paths:设置各模块的别名和路径,在调用模块时需使用别名。资源文件路径可以是本地路径,也可以是外部的链接,也可以设置多个路径,路径可以是一个字符串路径,也可以是一个数组,当存在两个或以上路径时必须是数组。
以JQ路径为例,单个路径"jquery": ["lib/jquery-1.8.3.min"]
多个路径"jquery": ["http://apps.bdimg.com/libs/jquery/1.8.3/jquery.min.js","lib/jquery-1.8.3.min"],多个路径时会先获取第一个路径的资源文件,第一个路径加载失败则会加载第二个路径(注意:本人实践中第一个路径使用CDN时在IE11以下的IE浏览器会加载失败且没有调用本地资源,原因未知)
shim:非AMD规范的模块不能直接调用,该属性用于设置非AMD规范的模块,属性值是一个对象,本人写的弹框插件非AMD规范因此需要设置,设置的模块名称和所依赖的模块名称需是该模块在paths定义的别名。deps用于设置该模块的依赖,popup插件依赖于JQ

define(name,deps,callback)函数

单从语义就应该猜到这个函数用来定于模块,下面解释define函数,若看不懂别着急,后面会举例。
在require.js源码中可以看到有这么一行代码define = function (name, deps, callback) {} ,可知define接收三个参数
name:为可选参数,该模块的标识,字符串类型,通俗来讲就是给该模块取的名称,可自定义,但不能与其他模块名称相同,如果该参数未选,那么该模块的名称为该文件在paths中定义的别名
deps:当前模块的依赖,数组类型,为已定义的模块名称,若不存在依赖该参数可不填
callback:是一个函数或者对象,为函数时,当依赖的模块加载完成后该回调函数将被调用,依赖关系会以参数的形式注入到该函数上,参数与依赖的模块一一对应,(注:如果定义的模块想被其他模块引用需返回一个对象)。

通过define定义模块的方式可分为以下两类。

1. 无依赖模块
也就是说该模块无需依赖其他模块,可以直接定义,如下:

例1

 define({
        fnMethod: function() {
            return ("这是一个无依赖模块")
        }
    });

该模块只传了一个对象类型的callback,也等价于

例2

 define(function() {
        return {
            fnMethod: function () {
                return ("这是一个无依赖模块")
            }
        }
    });

该模块则传了一个函数类型的callback,模块定义了一个函数fnMethod,返回一个字符串值,实际上返回值也可以是其他类型,第二种方法只是将函数做为对象返回,建议采用第二种方法来定义无依赖模块。

2. 有依赖模块
定义有依赖模块格式需要稍作改变,格式如下:

例3

//假如moduleA模块返回了一个属性name,值为“老宋”,
老马
define(["jquery","moduleA"],function($, mA) { //参数和依赖的模块需一一对应 return { fnMethod: function () { return ($.text(".text") + mA.name); } } });

该例子表明当前模块依赖于jquery和moduleA,返回一个结果“老马老宋”。
沿用上面的例子再举一个完整的例子:

例4

define("module",["jquery","moduleA"],function($, mA) {    //参数和依赖的模块需一一对应
        return {
            fnMethod: function () {    //fnMethod即提供给外部调用的接口
                return ($(".text").text() + mA.name);
            }
        }
 });

这里定义了一个名为module的模块,并且它依赖于jquery和moduleA模块。

当依赖的模块很多的时候再像下面这样写感觉是不是很挫?

例5

define("module", ["jquery", "moduleA", "moduleB", "moduleC", "moduleD", "moduleE", "moduleF"], function ($, mA, mB, mC, mD, mE, mF) {
        return {
            fnMethod: function () {
                return ($(".text").text() + mA.name);
            }
        }
    });

require.js2.0版本之后提供了一种更好的写法。

例6

   define("module", function (require) {    //将“require”本身做为一个依赖注入到模块
    var $ = require("jquery"),
        mA = require("moduleA"),
        mB = require("moduleB"),
        mC = require("moduleC"),
        mD = require("moduleD"),
        mE = require("moduleE"),
        mF = require("moduleF");
    
    return {
        fnMethod: function () {
            return ($(".text").text() + mA.name);
        }
    }
});

注意以下几点:
1.当要在define内部使用require时,需将“require”本身做为一个依赖注入到模块,如例6,例5有依赖则可在依赖数组中加入,如无依赖不应将require加入依赖数组会报错,而要像例6一样做法。
2.require.js要求一个文件一个模块,意思就是一个文件只能有一个define定义的模块,如果一个文件存在多个define模块,也只会识别第一个(如果模块写在主文件则是另外一种情况,优化部分会讲解),上面例子的moduleA和moduleB等应存在不同文件中,define如果填了name参数,该name的名称必须与paths中该文件的别名一致。

require(deps, callback, errback)函数

require()用来调用模块,使用方法与define()类似,require.js源码中有这么一行return context.require(deps, callback, errback),可知require()也有三个参数。

  require(["moduleA", "moduleB"], function (mA, mB) {
        console.log(mA.name);
        console.log(mB.age);
    },
    function (error) {
        //....
    }
);

当moduleA和moduleB这两个模块加载完成之后将会执行回调函数。
第一个参数依然是依赖关系数组;
第二个参数是依赖加载成功后的回调函数;
第三个参数则是处理错误的回调函数,接收一个error对象参数,require对象还允许指定一个全局性的Error事件的监听函数。所有没有被上面的方法捕获的错误,都会被触发这个监听函数。

requirejs.onError = function (error) {
    // ......
};

require也可以下在define内部使用,如下:

define("moduleA",function (require) {
    //.......
    require(["moduleB, moduleC"], function(mB, mC) {
        //.......
    });
    //.....
});

require可以直接调用JSONP模式,只需将callback参数的值指定为"define",

require(["http://example.com/api/data.json?callback=define"],
    function (data) {
         console.log(data);
    }
);

上面是一个调用JSONP的示例,该例子中,JSONP的callback参数为"callback",因此"callback=define"告诉API将JSON响应包裹到一个"define()"中,JSONP的这种用法应仅限于应用的初始化中,一旦JSONP服务超时,其他通过define()定义了的模块也可能得不得执行。
仅支持返回值类型为JSON object的JSONP服务,其他返回类型如数组、字串、数字等都不能支持。

require.js插件

require.js支持加载插件,用来加载其他非JS文件,下载插件并将它放在应用程序的baseUrl目录(如果想放在其他地方,使用paths config 进行配置),更多更详细的插件可查看官方文档,示例以domReady插件,text插件为例。
domReady插件可以使回调函数在DOM结构加载完成之后再执行。

require(["domReady"], function (domReady) {
  domReady(function () {
    //This function is called once the DOM is ready.
    //It will be safe to query the DOM and manipulate
    //DOM nodes in this function.
  });
});

 

require(["domready!"], function (doc){
    //This function is called once the DOM is ready.
       //It will be safe to query the DOM and manipulate
       //DOM nodes in this function.
});

text.js插件
相比于使用script构建DOM结构,使用HTML标签来构建html是一个很好的方式。然而, 并没有很好的方式可以在js文件中嵌入 HTML 。最好的方式是使用 HTML字符串, 但这很难管理,尤其实在多行HTML的时候。text.js 能解决这个问题,如果依赖添加了 text!前缀它将会被自动加载。

require(["text!/view/index.html" ,"text!/css/tab.css"],
    function(html, css) {
        //........
    }
);

上面示例加载的文件内容将以字符串的形式存在变量中。

优化

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80934.html

相关文章

  • 前端块化详解(完整版)

    摘要:二模块化规范概述应用由模块组成,采用模块规范。模块化语法命令用于规定模块的对外接口,命令用于输入其他模块提供的功能。 前言 在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀,此时...

    Sanchi 评论0 收藏0
  • 前端块化详解(完整版)

    摘要:二模块化规范概述应用由模块组成,采用模块规范。模块化语法命令用于规定模块的对外接口,命令用于输入其他模块提供的功能。 前言 在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀,此时...

    Pines_Cheng 评论0 收藏0
  • 前端工程师必备:前端的块化

    摘要:规范则是非同步加载模块,允许指定回调函数,可以实现异步加载依赖模块,并且会提前加载由于主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以规范比较适用。 JS模块化 模块化的理解 什么是模块? 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起; 块的内部数据/实现是私有的, 只是向外部暴露一些接口(...

    Render 评论0 收藏0
  • [Webpack并不难]使用教程(一)--- entry,devtool,output,resol

    摘要:这是局部安装局部安装的使用要带路径哇,要写路径,好麻烦哦,没事,那就全局安装吧。如果该值是一个相对路径,它将相对于包含的文件。就相当于就相当于就相当于后面带有意味着要完全匹配如果,因为没完全匹配,那么加载的是下文件夹里的使用教程二 Webpack是什么,我就不过多介绍了,大家都有耳闻,不过还是配张图让大家体会下。showImg(https://segmentfault.com/img/...

    wudengzan 评论0 收藏0
  • Javascript模块全揽

    摘要:要求模块编写必须在真正的代码之外套上一层规定的代码包装,样子看起来是这样的模块代码通过传递一个签名为的回调函数给函数,就可以把需要注入的变量和函数注入到模块代码内。 之前写的文章急速Js全栈教程得到了不错的阅读量,霸屏掘金头条3天,点赞过千,阅读近万,甚至还有人在评论区打广告,可见也是一个小小的生态了;)。看来和JS全栈有关的内容,还是有人颇有兴趣的。 showImg(https://...

    lily_wang 评论0 收藏0

发表评论

0条评论

fox_soyoung

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<