前端模块化-requireJS教程

作者:超级管理员 浏览数:136 发布时间:2024-08-26

一、什么是 RequireJS 

RequireJS 用于代码模块化,RequireJS 以一个相对于 baseUrl 的地址来加载所有的模块代码,使用 RequireJS 来开发,可以很好的避免变量污染全局环境。它的模块管理遵守AMD (Asynchronous Module Definition)规范,通过 define 方法来完成模块的定义以及模块代码的加载。 

二、RequireJS 使用 

1、引入 require.js

<script src="js/require.js" defer async="true" data-main="js/main"></script>

<script>标签含有一个特殊的属性 data-main,后面的属性值是一个 main.js 文件,后缀 .js 可要可不要,因为 RequireJS 默认它就是一个 .js 文件。这个 main.js 文件就相当于一个入口,用来加载你定义的所有模块。defer和async="true"就是让 js 文件延迟下载,如果你是在 head 标签里引入 js 文件,那么使用这两个属性中的一个就可以实现文件的异步加载(下载)。以下是简单例子:

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title>RequireJS 教程详解</title>

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

</head>

<body>

    <div>RequireJS 真的很实用,很方便。</div>

</body>

</html>

页面请求时开始加载这个 .html 页面,当代码运行到这一行时就开始请求、下载 require.js 文件,如果我们不加defer或者 async="true"的话,只有等 require.js 这个文件下载完后才开始继续解析script 标签以下的HTML代码,这就很容易造成页面空白,这也就是我们常说的阻塞。而加了defer或者async="true"就可以让你实现异步加载文件(下载 require.js 文件的同时,继续解析 script 标签后面的 HTML 代码)。当然如果你是放在页面的最后,那加不加defer或者async="true",也没什么意义了。虽然defer和async="true",在上面作用差不多,但其实他们是有区别的,defer是等所有的 .js 文件都下载完后才会执行程序,而async 则不同,只要下载完一个就执行一个,有点今朝有酒今朝醉的味道。

2、配置 main.js 文件 

这个文件除了是模块的入口以外,你还可以在这里配置一些基本的信息。比如:指定模块的默认路径、定义第三库依赖关系、别名配置等。 简单的config 配置:

// main.js:

require.config({ 

    baseUrl: "/wp-content/themes/zxxplus/assets/js/modules", 

    paths: { "jquery": "/wp-content/themes/zxxplus/assets/js/lib/jquery.min",

                "prettify": "/wp-content/themes/zxxplus/assets/js/lib/prettify.min"},

}); 

在这里我就以我的主题为例,这样分析起来可能会让你感觉更体贴,也更好理解。 

baseUrl:这里的 baseUrl 为什么要那么长?因为如果你不以站点根目录开始的话,你会发现浏览器会给你报错找到不某某 .js 文件。 

注意:RequireJS 默认的 baseUrl 为包含 RequireJS 的那个 HTML 页面的所在目录。

paths:这个可以理解成给一些文件起来别名,比如上面的 jquery,prettify。当某个模块需要引用这些库(如:jquery)时,你可以直接使用 jquery 就可以了。RequireJS 可能通过它来获取到真正的 jquery.min.js 文件。 

3、模块定义

3.1 简单的键值对模块定义(setting-var.js) 

// setting-var.js

define(function(){

    return{

        GUIDEIDGET:false,

        NAVWIDGET:false,

        SCREENWIDGET:false,

        READMODE:false

    }

});

//或者

define({

    GUIDEIDGET:false,

    NAVWIDGET:false,

    SCREENWIDGET:false,

    READMODE:false

});

上面的两种方法可以二选一,建议使用第二种方法,更加简洁。在这个模块里定义了这些变量后,你就可以在其它需要这个变量的模块中引入这个变量模块并且使用这些变量。 

3.2 函数模块定义

 // save-setting-widget

define(function(){

return{

    save: function(_json){

        localStorage.setItem("ykdata",JSON.stringify(_json));

    },

    get: function(_json){

        if(localStorage.ykdata){

            return JSON.parse(localStorage.getItem("ykdata"));

        }else{

            return _json //默认设置_json

        }

    }

}

});

上面的代码实现什么功能不重要,重要的是你得能通过上面的代码知道 RequireJS 定义函数模块的套路。上面是以键值对的形式定义函数,这样做是为了让外部调用这个模块里的方法。如果你是一个功能模块,那么你也可以像下面这样写(prettify-widget.js),在通过 return 把这个函数暴露出去供其它模块调用,或者在 main.js 方法中加载这个模块。 

// prettify-widget.js

define(["jquery","prettify"],function ($,prettify){

    function prettifyWidget() {

        $("pre").addClass("prettyprint linenums");

         prettyPrint();

    }

    return{

        prettifyWidget : prettifyWidget

    }

});

上面的这个模块还用到了 jquery 和 prettify 第三方库,所以就得像上面那么引入它们,上面的 jquery 和 prettify 就是我们前面require.config里配置的别名,别名的好处相信你应该领悟到了。

 注意:后面的匿名函数 function ($,prettify){……} 里的变量是跟你引入的模块一一对应的。

 如果要在模块中引用自己写好的模块也是同样的道理(比如 setting-var.js 和 save-setting-widget.js),真的把你的模块名像上面那样传进去就可以了。 

// nav-widget.js

define(["jquery","setting-var","save-setting-widget"],function ($,sv,ssw){

function navWidget(){

    var navWidgetButton = $("#nav-widget-button");

    var temp = ssw.get(sv);

    if(temp.NAVWIDGET){

        action();

    }

    navWidgetButton.click(function(){

        action($(this));

        temp.NAVWIDGET = !temp.NAVWIDGET;

        ssw.save(temp);

    });

    function action(_obj){

        _obj = _obj || navWidgetButton;

        $("#nav-widget").toggleClass("nav-widget");

        $("#container-control").toggleClass("nav-extra");

        if(_obj.html() == "置顶<br>导航"){

            _obj.html("侧边<br>导航");

        }else{

            _obj.html("置顶<br>导航")

        }

    }

}

    return{

          navWidget : navWidget

    }

});

注意 :

(1)因为一开始我们已经设置了默认的baseUrl: "/wp-content/themes/zxxplus/assets/js/modules",所以引入了一个模块名后,RequireJS 就会很自觉地到这个目录下找到这个模块(.js 文件),并加载进来。 

(2)但是,当加载纯.js文件(比如:依赖字串以/开头,或者以 .js 结尾,或者含有协议http://、https://),不会使用baseUrl。 

4、加载模块 

模块写好了,最后一部就是在 main.js 入口文件中加载这些模块。

// 基本配置

require.config({

    baseUrl: "/wp-content/themes/zxxplus/assets/js/modules/",

    paths: {

        "jquery": "/wp-content/themes/zxxplus/assets/js/lib/jquery.min",

        "prettify": "/wp-content/themes/zxxplus/assets/js/lib/prettify.min"

    }

});

// 加载模块

require(["nav-widget"],function(fn){

    fn.navWidget();

});

require(["prettify-widget"],function(fn){

    fn.prettifyWidget();

});