require.js(初篇)

一、关于模块化编程

1.1传统代码的缺陷

随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿。

原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,并且这样写有很大的 缺点,

首先,加载的时候,浏览器会停止网页的渲染,加载的文件越多,那么网页失去响应的时间越长,

其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序,依赖性大的模块一定要放在最后加载,当依赖关系很复杂的时候,代码的编写和维护都会非常困难。

所以我们需要团队协作、模块复用、单元测试等等一系列复杂的需求。

二、什么是模块化及模块化编程规范

模块化是只在处理某些问题的时候,按照一种分类思想对功能进行模块化的管理和使用。

2.1 require.js的诞生

require.js的诞生就是为了解决上述<script>加载问题。

AMD

require.js加载的模块,采用AMD规范。也就是说,模块必须按照AMD的规定来写。即需要用define()来定义模块和require(),后续会介绍如何定义模块

对于模块化的发展暂不做详细介绍,百度很6的~

2.2require.js的的加载

先去官网下载最新版本,下载后,可以选择把它放在文件的根目录下或者是js文件下
<script type="text/javascript" src="js/require.js" ></script>

为了避免加载文件的时候造成网页失去响应。解决办法有俩个,一个是把文件的加载放在网页的最底部,一个是写成下面这样
<script src="js/require.js" async="async" ></script>
async属性表明这个文件需要异步加载,避免网页加载的时候失去响应。

加载require.js之后,需要加载我们自己的js文件代码,假设我们自己的代码文件是app.js,也放在根目录下,那么就写成下面这样
<script type="text/javascript" src="js/require.js" data-main="app"></script>
data-main这个属性的作用是指定我们网页程序的主模块。这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把app.js简写成app。

2.3 主模块的写法

一旦我们定义了主模块的js文件,意思这个就是整个网页的入口代码,所有的代码都从这开始运行。

如果主模块代码不依赖于其他任何模块,那么可以直接写JavaScript代码。

这样就失去了require.js的意义了,因为正常情况下,主模块都会依赖于其他模块,这时就需要遵守AMD规范。

看栗子,格式像这样

      // app.js
      require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
       .......
      });

require()函数
require()函数接受两个参数。
第一个参数是一个数组,表示程序所依赖的模块,即主模块依赖['moduleA', 'moduleB', 'moduleC']这三个模块;
第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块要以参数形式传入回调函数,从而在回调函数内部就可以使用这些模块。

举个栗子

require(["a","b","c"],function(A,B,C){
      .....something.....
})

此时各个模块之间的关系是这样的,index.html和app.js和modules文件架 在根目录下,modules文件下有moduleA,moduleB,moduleC三个文件夹,里边分别有a.js 和 b.js 和 c.js。

捕获.PNG

require.js会先加载'a', 'b', 'c',然后再运行回调函数。主模块的代码就写在回调函数中。

2.4模块的加载

上一节的栗子中,主模块的依赖模块是'a', 'b', 'c'
文件名分别为a.js ,b.js ,c.js 然后自动加载

使用require.config()方法,我们可以对模块的加载行为进行自定义。require.config()就写在主模块(app.js)的头部。参数就是一个对象,这个对象的paths属性指定各个模块的加载路径。

栗子

//通过require.config方法来配置要导入的模块路径
require.config({
    paths:{
        //这里写要导入的路径和对应生成的模块名字
        a:"modules/moduleA/a",
        b:"modules/moduleB/b",
        c:"modules/moduleC/c"
    }
})

另注
1.如果模块在另一台主机上,也可以直接指定它的网址。
2.如果在这文件在同在其他弄一个文件夹内,比如都在lib文件架内,也可以指定baseUrl

2.5 AMD定义模块

AMD模块必须采用define()函数来定义

1.如果一个模块不依赖于其他模块,那么可以直接定义在define()函数中。

假设上栗中的a.js模块不依赖于其他模块,那么a.js中的代码如下

//define定义模块(不依赖于任何其他模块)
define(function () {
    //加法运算
    function add (x, y) {
        return x + y;
    }
    
    return {
        add : add
    }
})

2.定义模块的时候如果有依赖于其他模块的话,我们就可以把第一个参数加入,第一个参数是一个数组,数组中就是依赖模块的名字或者路径。

如果这里写路径,注意是相对于app.js而言的路径

假设上栗中的b.js是依赖于jquery和a.js模块的,那么我们可以在第一个参数中引入,代码如下

//定义模块的时候如果有依赖于其他模块的话,我们就可以把第一个参数加入
//第一个参数是一个数组,数组中就是依赖模块的名字或者路径
//如果这里写路径需要注意是相对于app.js而言的路径
define(['jquery', './modules/moduleA/a'], function ($, A) {
    //改变div颜色
    function changeColor () {
        $("#box").css({
                       //将div的北京变成蓝色
            backgroundColor : "red"
        });
    }
    
    //私有方法(说白了就是给自己用,不支持导出这个功能)
    //计算两数之差
    function mul (x, y) {
        return x - y;
    }
    
    function addAndMul (x, y) {
       //调用自身的两个函数
        changeColor();
        //用到了A模块里的功能和自身模块的私有方法
        return A.add(x, y) + mul(x, y);
    }
    //因为后续数据需要反馈,所以一定要return
    return {
        addAndMul : addAndMul
    }
    
});

当require()函数加载上面这个模块的时候,就会先加载他所依赖的模块。

3.为了方便理解下面内容,我们在c.js中也定义一个模块,其代码如下

define(['a', 'b'], function (A, B) {
    function changeColor () {
        $("#box").css({
            //将div的背景变成蓝色
            backgroundColor : 'blue'
        });
    }
    
    function fn (x, y) {
        changeColor();
        return  A.add(x, y) + B.addAndMul(x, y);
    }
    //因为后续数据需要反馈,所以一定要return
    return {
        fn : fn
    }
});

2.6 模块的调用

此时我们定义了了三个模块。分别为a.js 和b.js 和 c.js,并在主模块app.js中引入了三个模块。

此时我们需要调用这三个模块,并发挥他们的功能,因此,在app.js中,我么除了引入三个模块的路径,还需要调用,代码如下

//通过require方法来导入模块
//如果上面配置了路径,数组里导入的时候直接就可以写上面路径对应的模块名字即可
//jquery比较特殊,叫jquery以外其他名字的话,导出模块会是undefined
//注意:模块支持导出的话,一定要对应上,不支持导出的模块,我们放在数组中的最后
require(['jquery', 'a', 'b', './modules/moduleC/c'], function (j, A, B, C) {
    console.log($);
    console.log(j);
    //使用A模块的功能
    console.log(A.add(1, 2));
    //使用B模块的功能
    console.log(B.addAndMul(1, 2));
    //使用C模块的功能
    console.log(C.fn(1, 2));
});

调用了app.js需要依赖的a,b,c三个模块,又进行了引用,那么此时app.js中的全部代码如下

//通过require.config方法来配置要导入的模块路径
require.config({
    paths : {
        //这里写要导入的路径和对应生成的模块名字
        jquery : './lib/jquery',
        a : './modules/moduleA/a',
        b : './modules/moduleB/b'
    }
})

//通过require方法来导入模块
//如果上面配置了路径,数组里导入的时候直接就可以写上面路径对应的模块名字即可
//注意:模块支持导出的话,一定要对应上,不支持导出的模块,我们放在数组中的最后
require(['jquery', 'a', 'b', 'modules/moduleC/c'], function (j, A, B, C) {
    //使用A模块的功能
    console.log(A.add(1, 2));
    //使用B模块的功能
    console.log(B.addAndMul(1, 2));
    //使用C模块的功能
    console.log(C.fn(1, 2));
});

注意代码中c模块的变化了么?你再仔细瞅瞅?说好的引用呢?
温馨提示,也要注意b和c里面的代码哦

如果在配置依赖的模块路径没有配置,那么在require调用的时候,在数组参数中写其路径也是可以的。

主页面index.html中没有实际的内容,只是引用,代码如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style type="text/css">
            #box{
                width: 200px;
                height: 200px;
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div id="box"></div>
        <!-- 导入requireJS库 -->
        <!-- data-main可以导入主入口文件app是指app.js -->
        <script type="text/javascript" src="lib/require.js" data-main="app"></script>
    </body>
</html>

此时运行index.html ** 注意 div的颜色。。**

运行结果(1).jpg

你觉得对么?按照加载的顺序,应该最后加载c.js div的颜色怎么是红色的?应该是蓝色的才对?

因为我们在c.js中return的时候,又调用了b.js,所以最后又加载了b.js,所以,div变成了红色~那么,如何解决这个问题呢?用变量存起来不就好啦 -,c.js中的代码如下

define(['a', 'b'], function (A, B) {
    function changeColor () {
        $("#box").css({
            backgroundColor : 'blue'
        });
    }
    
    function fn (x, y) {
        var num = A.add(x, y) + B.addAndMul(x, y);
        changeColor();
        return num;
    }
    
    return {
        fn : fn
    }
});
此时我们再输出一下结果
运行结果(2).jpg

此篇文章助大家理解require.js,真正的require.js用法,可没这么简单呢

不要吝啬赞美,喜欢就点赞啦

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • requirejs是一个JavaScript文件和模块加载器。requireJS允许你把你的javascript代...
    GQ1994阅读 2,195评论 0 58
  • 本文参照阮老师的文章。一、为什么要用require.js?最早的时候,所有Javascript代码都写在一个文件里...
    索哥来了阅读 281评论 0 3
  • JS中的模块规范(CommonJS,AMD,CMD),如果你听过js模块化这个东西,那么你就应该听过或Common...
    小虾米前端阅读 4,377评论 0 12
  • 【20171107星期二】 “你要相信凡事皆有因果,面对挑战才能有好事降临。” 很巧,上面这句话是在18:22分的...
    Lan宝石的练习室阅读 305评论 0 0
  • 在小学时的我,老是跟一群朋友出去玩,一起吸烟,一起喝酒,一起以大欺小 ,一起上网吧,一起玩电子,赢钱的时候还是开心...
    I喜你耶阅读 369评论 1 3