[RequireJS]入门API

§ 1. 用法

§ 1.1. 加载js脚本文件

为了鼓励模块化开发,使用模块ID来进行模块代码加载。

RequireJS通过baseUrl的相关路径来进行代码加载。

baseUrl一般设置为 data-main属性对应文件的父目录。

(RequireJS会检查并运行data-main所指定的脚本)

html内设置baseUrl的代码如下:

<!--This sets the baseUrl to the "scripts" directory, and
    loads a script that will have a module ID of 'main'-->
<script data-main="scripts/main.js" src="scripts/require.js"></script>

baseUrl也可以通过config来进行手动设置。

如果没有使用script标签,或config进行设置,baseUrl将会是运行RequireJS的html文件目录。

RequireJS默认以"baseUrl和paths"方式加载脚本,如果不想使用baseUrl和paths的方式加载脚本,可以是使用下面的方法:

1.带".js"结尾

2.以"/"开始

3.含"http:"或"https:"的url地址

 

如果想要清晰的分割目录结果,可以使用下面的方法,但不推荐


www/

    • index.html
    • js/
      • app/
        • sub.js
      • lib/
        • jquery.js
        • canvas.js
      • app.js

index.html:

<script data-main="js/app.js" src="js/require.js"></script>

app.js:

requirejs.config({
    //By default load any module IDs from js/lib
    baseUrl: 'js/lib',
    //except, if the module ID starts with "app",
    //load it from the js/app directory. paths
    //config is relative to the baseUrl, and
    //never includes a ".js" extension since
    //the paths config could be for a directory.
    paths: {
        app: '../app'
    }
});

// Start the main app logic.
requirejs(['jquery', 'canvas', 'app/sub'],
function   ($,        canvas,   sub) {
    //jQuery, canvas and the app/sub module are all
    //loaded and can be used here now.
});

RequireJS也可以引用用户自己通过define()方法定义的模块,且可以定义该模块的依赖模块

另外,对于浏览器级别的脚本的,不能通过define()来定义依赖模块,需要通过shim config来定义他们的依赖模块

 

§ 1.2. data-main 入口

代码如下:

<!--when require.js loads it will inject another script tag
    (with async attribute) for scripts/main.js-->
<script data-main="scripts/main" src="scripts/require.js"></script>

data-main 可以同时设置config与入口模块

RequireJS无法保证 data-main 模块会优先于 其他通过<script>标签引用的脚本 被加载完成并执行。

例如下面的代码有时会执行失败:

<script data-main="scripts/main" src="scripts/require.js"></script>
<script src="scripts/other.js"></script>
// contents of main.js:
require.config({
    paths: {
        foo: 'libs/foo-1.1.3'
    }
});

// contents of other.js:

// This code might be called before the require.config() in main.js
// has executed. When that happens, require.js will attempt to
// load 'scripts/foo.js' instead of 'scripts/libs/foo-1.1.3.js'
require(['foo'], function(foo) {

});

如果想在html使用require()方法,只用引用RequireJS,不要加data-main属性即可,例如:

<script src="scripts/require.js"></script>
<script>
require(['scripts/config']), function() {
    // Configuration loaded now, safe to do other require calls
    // that depend on that config.
    require(['foo'], function(foo) {

    });
});
</script>

 

§ 1.3. 定义模块

模块定义使用了命名空间与作用域来避免冲突

模块罗列了他的依赖模块,并将依赖模块作为参数传入

RequireJS的异步加载模块,使得她速度快,也因为他没有定义全局模块,使得她可以在一个页面里同时加载不同版本的同一个模块。

(RequireJS模块可以转换为CommonJS模块)

每个模块必须定义在一个文件里,这些模块可以通过优化工具,被打包压缩。

 

§ 1.3.1. 简单键/值对[json格式类似] 没有依赖模块,没有方法,只有数据

//Inside file my/shirt.js:
define({
    color: "black",
    size: "unisize"
});

§ 1.3.2. 定义方法

没有依赖模块,但需要处理些事情准备时的定义模块方法:

//my/shirt.js now does setup work
//before returning its module definition.
define(function () {
    //Do setup work here

    return {
        color: "black",
        size: "unisize"
    }
});

§ 1.3.3. 含依赖模块的定义

第一个参数是,依赖模块名数组,第二个参数是回调方法,该回调方法的形参是依赖模块(且顺序一致),返回一个对象

到所有依赖模块加载完毕后,才会调用回调方法,该模块不是全局模块。

代码如下:

//my/shirt.js now has some dependencies, a cart and inventory
//module in the same directory as shirt.js
define(["./cart", "./inventory"], function(cart, inventory) {
        //return an object to define the "my/shirt" module.
        return {
            color: "blue",
            size: "large",
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
);

§ 1.3.4. 用方法的形式定义模块

模块返回值不一定为对象,下面就是返回方法的模块定义方法:

//A module definition inside foo/title.js. It uses
//my/cart and my/inventory modules from before,
//but since foo/title.js is in a different directory than
//the "my" modules, it uses the "my" in the module dependency
//name to find them. The "my" part of the name can be mapped
//to any directory, but by default, it is assumed to be a
//sibling to the "foo" directory.
define(["my/cart", "my/inventory"],
    function(cart, inventory) {
        //return a function to define "foo/title".
        //It gets or sets the window title.
        return function(title) {
            return title ? (window.title = title) :
                   inventory.storeName + ' ' + cart.name;
        }
    }
);

§ 1.3.5. 简单CommonJS模块的兼容定义

需要直接引用模块名,代码如下:

define(function(require, exports, module) {
        var a = require('a'),
            b = require('b');

        //Return the module value
        return function () {};
    }
);

该格式需要Function.prototype.toString()方法获取方法内容,不能在PS3和一些旧Opera浏览器中使用,但在优化工具优化压缩后正常运行。

§ 1.3.6. 定义带模块名的模块

模块名作为define()的第一个参数

//Explicitly defines the "foo/title" module:
    define("foo/title",
        ["my/cart", "my/inventory"],
        function(cart, inventory) {
            //Define foo/title object in here.
       }
    );

模块命名一般有优化工具自动生成,也可以自己命名,但是一旦移动目录后,就需要重新命名,不太灵活,而且自动优化工具能过自动命名,并且在一个文件里存放多个模块,可以让浏览器加载更快。

§ 1.3.7. 其他的模块方面的提示:

1.一个js文件,一个模块。 可以使用优化工具,将开发完的所有代码优化后,会进行压缩,整合

2.可以在模块内部使用require方法

define(["require", "./relative/name"], function(require) {
    var mod = require("./relative/name");
});
define(function(require) {
    var mod = require("./relative/name"); });
 

3.生成相对于模块的url

define(["require"], function(require) {
    var cssUrl = require.toUrl("./style.css");
});

4.控制台内的调试

对于已经加载的模块,可以通过下面方法获取他

require(["module/name"], function(){}) 

require("module/name").callSomeFunction()

相对路径只在内部定义可用。

§ 1.3.8. 循环依赖

"a" needs "b" and "b" needs "a"

b内的a为null

应该用下面方法:

//Inside b.js:
define(["require", "a"],
    function(require, a) {
        //"a" in this case will be null if "a" also asked for "b",
        //a circular dependency.
        return function(title) {
            return require("a").doSomething();
        }
    }
);

也可以使用CommonJS模块的方法,但是必须每个模块返回的都是对象,而不是方法

//Inside b.js:
define(function(require, exports, module) {
    //If "a" has used exports, then we have a real
    //object reference here. However, we cannot use
    //any of "a"'s properties until after "b" returns a value.
    var a = require("a");

    exports.foo = function () {
        return a.bar();
    };
});

//Inside b.js:
define(['a', 'exports'], function(a, exports) {
    //If "a" has used exports, then we have a real
    //object reference here. However, we cannot use
    //any of "a"'s properties until after "b" returns a value.

    exports.foo = function () {
        return a.bar();
    };
});

§ 1.3.9. 特别的JSONP服务的依赖

JSONP:js通过http Get方法的跨域调用WebService的方法

通过回调参数获取JSONP URL返回的数据

代码如下:

require(["http://example.com/api/data.json?callback=define"],
    function (data) {
        //The data object will be the API response for the
        //JSONP data call.
        console.log(data);
    }
);

注:JSONP的使用,最好只限于初期数据的取得,因为到JSONP超时,会导致依赖他的模块无法执行,也无法对JSONP超时做出充分的错误处理

只有JSONP返回JSON数据时,才能使用该方法。返回数组,字符串或数字时,不能使用该方法。且不适用于长轮询JSONP,如果查复通过同一个JSONP URL获取,只能获取到缓存数据

你可以重写requirejs.onError()方法去捕获错误。

§ 1.3.10. 解除模块定义

RequireJS里有一个全局函数requirejs.undef()可以用来解除模块定义,但是无法移除已经依赖完成的模块内的定义,一般用于错误时的处理

 

§ 2. 原理

RequireJS的加载依赖JavaScript模块是通过 head.appendChild() 来实现的

RequireJS会按照正确的顺序加载脚本模块

如果用于服务器端时,可以修改require.load()方法,使得RequireJS同步加载脚本模块

require.load位于 build/jslib/requirePatch.js

 

§ 3. 配置选项

§ 3.1. 可以直接在html内配置

<script src="scripts/require.js"></script>
<script>
  require.config({
    baseUrl: "/another/path",
    paths: {
        "some": "some/v1.0"
    },
    waitSeconds: 15
  });
  require( ["some/module", "my/module", "a.js", "b.js"],
    function(someModule,    myModule) {
        //This function will be called when all the dependencies
        //listed above are loaded. Note that this function could
        //be called before the page is loaded.
        //This callback is optional.
    }
  );
</script>

也可以在data-main入口脚本文件里通过require.config 配置,但请注意,只能有一个data-main入口。

当然也可以在载入requireJS前,定义全局配置对象 require,如下:

<script>
    var require = {
        deps: ["some/module1", "my/module2", "a.js", "b.js"],
        callback: function(module1, module2) {
            //This function will be called when all the dependencies
            //listed above in deps are loaded. Note that this
            //function could be called before the page is loaded.
            //This callback is optional.
        }
    };
</script>
<script src="scripts/require.js"></script>

§ 3.2. 支持的配置选项

baseUrl: 查找所有模块的根目录。通过插件,可以做到跨域加载。

paths: 罗列了不从baseUrl里查找的模块。一般paths是相对于baseUrl的路径,除非是通过'/'或'URL形式'定义的路径

bundles: 打包定义模块,代码如下:

requirejs.config({
    bundles: {
        'primary': ['main', 'util', 'text', 'text!template.html'],
        'secondary': ['text!secondary.html']
    }
});

require(['util', 'text'], function(util, text) {
    //The script for module ID 'primary' was loaded,
    //and that script included the define()'d
    //modules for 'util' and 'text'
});

skim: 加载不能用define()定义的模块,如:全局定义,exports等非AMD规则库

例如下面:

requirejs.config({
    //Remember: only use shim config for non-AMD scripts,
    //scripts that do not already call define(). The shim
    //config will not work correctly if used on AMD scripts,
    //in particular, the exports and init config will not
    //be triggered, and the deps config will be confusing
    //for those cases.
    shim: {
        'backbone': {
            //These script dependencies should be loaded before loading
            //backbone.js
            deps: ['underscore', 'jquery'],
            //Once loaded, use the global 'Backbone' as the
            //module value.
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                //Using a function allows you to call noConflict for
                //libraries that support it, and do other cleanup.
                //However, plugins for those libraries may still want
                //a global. "this" for the function will be the global
                //object. The dependencies will be passed in as
                //function arguments. If this function returns a value,
                //then that value is used as the module export value
                //instead of the object found via the 'exports' string.
                //Note: jQuery registers as an AMD module via define(),
                //so this will not work for jQuery. See notes section
                //below for an approach for jQuery.
                return this.Foo.noConflict();
            }
        }
    }
});

//Then, later in a separate file, call it 'MyModel.js', a module is
//defined, specifying 'backbone' as a dependency. RequireJS will use
//the shim config to properly load 'backbone' and give a local
//reference to this module. The global Backbone will still exist on
//the page too.
define(['backbone'], function (Backbone) {
  return Backbone.Model.extend({});
});

关于使用 jQuery或Backbone插件,可以通过下面方式定义:

requirejs.config({
    shim: {
        'jquery.colorize': ['jquery'],
        'jquery.scroll': ['jquery'],
        'backbone.layoutmanager': ['backbone']
    }
});
requirejs.config({
    shim: {
        'jquery.colorize': {
            deps: ['jquery'],
            exports: 'jQuery.fn.colorize'
        },
        'jquery.scroll': {
            deps: ['jquery'],
            exports: 'jQuery.fn.scroll'
        },
        'backbone.layoutmanager': {
            deps: ['backbone']
            exports: 'Backbone.LayoutManager'
        }
    }
});

map: 给模块定义前缀,特别用于大型的,能够同时使用依赖模块的不同版本

requirejs.config({
    map: {
        'some/newmodule': {
            'foo': 'foo1.2'
        },
        'some/oldmodule': {
            'foo': 'foo1.0'
        }
    }
});

文件系统:

  • foo1.0.js
  • foo1.2.js
  • some/
    • newmodule.js
    • oldmodule.js

When 'some/newmodule' does `require('foo')` it will get the foo1.2.js file, and when 'some/oldmodule' does `require('foo')` it will get the foo1.0.js file.

只有在AMD规范下才起作用,且必须使用绝对路径。

也支持*号

requirejs.config({
    map: {
        '*': {
            'foo': 'foo1.2'
        },
        'some/oldmodule': {
            'foo': 'foo1.0'
        }
    }
});

Means that for any module except "some/oldmodule", when "foo" is wanted, use "foo1.2" instead. For "some/oldmodule" only, use "foo1.0" when it asks for "foo".

config: 可将配置下发至模块的配置:

requirejs.config({
    config: {
        'bar': {
            size: 'large'
        },
        'baz': {
            color: 'blue'
        }
    }
});

//bar.js, which uses simplified CJS wrapping:
//http://requirejs.org/docs/whyamd.html#sugar
define(function (require, exports, module) {
    //Will be the value 'large'
    var size = module.config().size;
});

//baz.js which uses a dependency array,
//it asks for the special module ID, 'module':
//https://github.com/jrburke/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#wiki-magic
define(['module'], function (module) {
    //Will be the value 'blue'
    var color = module.config().color;
});

也可为包配置:

requirejs.config({
    //Pass an API key for use in the pixie package's
    //main module.
    config: {
        'pixie/index': {
            apiKey: 'XJKDLNS'
        }
    },
    //Set up config for the "pixie" package, whose main
    //module is the index.js file in the pixie folder.
    packages: [
        {
            name: 'pixie',
            main: 'index'
        }
    ]
});

packages: 配置从commonJS模式包里加载模块

nodeIdCompat: 使得带js后缀与不带的模块ID相同

waitSeconds: 加载超时时间。0:无超时,默认7秒

context: 多版本支持

deps: 依赖

callback: 依赖模块加载完后的回调

enforceDefine: 若模块没有define()或shim exports string value会报错

xhtml: true时,会用document.createElementNS() 创建脚本元素

urlArgs: URL参数

urlArgs: "bust=" +  (new Date()).getTime()

在开发阶段有用

scriptType: 脚本类型版本,默认:text/javascript

skipDataMain: 跳过入口属性扫描直接加载模块,用于使用多个 由RequireJS开发的模块

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值