天天看點

RequireJS學習筆記前言加載javascript檔案子產品定義配置選項結語

前言

進入移動前端是很不錯的選擇,這塊也是我希望的道路,但是不熟悉啊。。。

現在項目用的是require+backbone,整個架構被封裝了一次,今天看了代碼搞不清楚,覺得應該先從源頭抓起,是以再看看require了。

上午是到處搜集的資料,下午我們來看原生的API吧:

http://www.requirejs.org/docs/api.html#config

PS:我英語很爛,各位将就着看吧,看到紅色就說明老夫拿不準......

加載javascript檔案

RequireJS采用不同的方法來加載腳本,他鼓勵子產品化程式設計,使用RequireJS程式設計不但可以子產品化程式設計而且他依舊可以運作的很快。

RequireJS鼓勵使用子產品ID,而不是像原來那樣使用script标簽使用url引入。

RequireJS加載代碼時候,其相對路徑為baseUrl,baseUrl通常被設定為data-main指定檔案的目錄:

<!--這裡講baseUrl設定為script的話,scripts/main.js便可以寫成main了-->
<script data-main="scripts/main.js" src="scripts/require.js"></script>      

BaseUrl也可以通過設定進行手動配置(通過RequireJS 的 config進行配置),若是沒在config中進行配置,并且script标簽沒有指定data-main的話,那麼預設目錄為引入requireJS的HTML頁面目錄。

預設情況下不要在子產品id上加上.js字尾,requireJS會在運作時自己加上。

通過設定config中的paths(對象字面量)屬性,你能設定一組腳本的位置,如此便能減少我們的js總體配置。

這裡我們來舉個例子,且看我們的文檔目錄:

RequireJS學習筆記前言加載javascript檔案子產品定義配置選項結語

我們index代碼:

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

app.js為入口函數,其代碼為:

requirejs.config({
    //預設情況下子產品所在目錄為js/lib
    baseUrl: 'js/lib',
    //當子產品id字首為app時,他便由js/app加載子產品檔案
    //這裡設定的路徑是相對與baseUrl的,不要包含.js
    paths: {
        app: '../app'
    }
});

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

各位請注意,這裡的jquery并沒有在他們的檔案名上加上其版本号,這裡推薦加上。

PS:原因我就不說了,說也不一定說得清楚......

理想情況下我們加載的腳步都會通過define()函數定義,但是我們有些腳步會依賴與目前版本不同的版本,你能使用shim配置,來表達其依賴。

PS:這裡有點模糊,我們再來看看snandy道友是怎麼說的:

shim參數解決了使用非AMD方式定義的子產品(如jQuery插件)及其載入順序。
使用shim參數來取代1.0版本的order插件。其實在1.0版本中就曾經有人開發過use和wrap插件來解決此類問題。
考慮到很多開發者有此類需求(比如某些JS子產品是較早時候其他人開發的,非AMD方式)此次2.0版本直接将其内置其中。      

這裡是一個使用jQuery插件形式配置的參數,我們知道jQuery插件本質是将命名空間挂在全局jQuery或jQuery.fn上,而非使用define定義的子產品。

jQuery插件皆依賴于jQuery,即在require插件時得保證jQuery先下載下傳:

1 require.config({
2     shim: {
3         'jquery-slide': ['jquery']
4     }
5 });
6 require(['jquery-slide']);      

這裡便會保證先加載jquery再加載插件。

PS:對照着園友的解釋看看吧,應該會清晰一點,這塊後面還會有我們等下再看。

子產品定義

requireJS定義子產品與傳統一個很大的不同是他可以保證其定義的變量處于某個範圍内,進而避免了全局命名污染。

他能明确的羅列出其依賴,并且在那些依賴上找到處理辦法,而不是必須對那些依賴指定全局變量。

requireJS的子產品擴充不需要全局變量與其他子產品産生依賴(了解的狗屁不通啊)

PS:文字讀不懂,來一個簡單的鍵值對例子吧:

define({
    color: "black",
    size: "unisize"
});      

若是這個子產品沒有任何依賴,并且他僅僅是一組鍵值對,那麼就傳遞一個對象就好。

定義函數

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

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

若是子產品沒有依賴,但是需要用一個函數做一些初始化工作,然後定義自己通過define的匿名函數。

有依賴的子產品

//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);
            }
        }
    }
);      

若是子產品具有依賴關系,第一個參數應該是一個數組,其項目為依賴名字,第二個參數是匿名函數

匿名函數在依賴項加載結束後會立即加載,函數會傳回一個對象用以定義這個子產品。

前面的依賴項将以參數的形式傳遞給函數,順序與之前一緻。

再看我們的例子,一個球衣子產品被建立了(我們傳回的是一個衣服子產品)

PS:這裡檔案命名為shirt.js,是以傳回的就是衣服子產品了

最後我們得到的結構式這樣的:

  • my/cart.js
  • my/inventory.js
  • my/shirt.js

參數調用時的參數與前面依賴項一一對應,

定義函數子產品

//A module definition inside foo/title.js. It uses
//my/cart and my/inventory modules from before,
//but since foo/bar.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;
        }
    }
);      

子產品也可以不必傳回對象,任何有效的傳回都是可以的,比如上面的例子,傳回一個函數作為其子產品定義。

帶名字的子產品

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

(???)這裡明确的定義了foo/title子產品,這裡其實是一種優化手段,我們這裡可以明确的命名子產品,但是若是檔案目錄變化我們就要更改名稱了。

其他說明

一個js檔案應該隻定義一個子產品,并與檔案目錄一緻,因為最後有個神馬優化工具可以優化。。。

在定義子產品時将各個子產品關聯起來,

相對子產品生産url,你可能需要使用一個相對子產品的url:

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

PS:尼瑪,我今天才知道我英語有多差。。。

循環依賴

我們有時候會定于循環依賴的子產品,比如a需要b并且b需要a,在這個情況下當b子產品調用時他将會從a獲得一個undefined值,b可以通過require方法取得一個比較晚的子產品。

//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();
        }
    }
);      

你通常不需要使用require方法擷取一個子產品,在循環依賴時候需要用到(讀不懂了。。。)

exports

//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();
    };
});      

配置選項

我們可以通過以下方法,對require進行配置:

<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>      

baseUrl

子產品查找的根目錄,預設情況與data-main所指派處于同一目錄

paths

該項用于配置那些不在baseUrl下的子產品,這個指定的path假定是baseUrl的相對路徑,若是以/開頭的話就不是了。

這裡的id會自動加上.js,我們要擷取一個路徑時,一般這個樣子幹:

require.toUrl()       

shim

傳統浏覽器的全局腳本不使用define去聲明依賴關系和子產品設定值的依賴。

Ps:讀不懂,還是看代碼算了:

requirejs.config({
    shim: {
        'backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                return this.Foo.noConflict();
            }
        }
    }
});

define(['backbone'], function (Backbone) {
    return Backbone.Model.extend({});
});      

這個例子假定backbone等依賴庫已經在baseUrl中,若是沒有就需要配置。

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'
        }
    }
});      

結語

讀不下去啦,暫時這樣吧。。。。。。

繼續閱讀