Requirejs常用配置和應用

來源:互聯網
上載者:User

標籤:fun   開發人員   efi   src   開發   script   fine   red   blank   

requirejs、require方法衝突

如果載入了多個requirejs指令碼,每個requirejs會判斷是否瀏覽器已經實現了require和define方法。如果瀏覽器已經內建require和define方法,或者之前已經有一個requirejs指令碼執行,那麼這個requirejs就會立刻停止執行。所以,即使頁面上載入了多次requirejs指令碼也不會有什麼問題。

配置Context

我把context叫做一個命名空間,因為每一個context都有一個名字,這樣同名而功能不同的模組就可以放在不同的context中以防衝突。

如果開發人員沒有配置context,那麼,requirejs還會產生一個預設的context,這個預設的context配置大致如下:

requirejs.config({

    context: "_",  // default context name

    baseUrl: "./",

    waitSeconds:7, // how long canloading last

    paths: {},

    bundles: {},

    pkgs: {},

    shim: {},

    config: {}

});

注意:在不指定context名稱的情況下,任何配置和調用都是針對預設context的修改和調用。

空間名稱 – context

如果requirejs初始化時自訂配置context,那麼預設建立的context的name 就是”_”。如果需要添加新的context,只需指定一個新的contextName即可,比如下面這個調用就會建立一個新的context:

requirejs({context:”new content name”});

同名的context只會有一個,配置同名的context等於修改這個context的屬性。

載入逾時 – waitSeconds

每個context都配置了一個載入逾時的時間,某個模組如果沒有初始化,載入的時間又超過了這個時間,就會被認為載入失敗。

載入逾時是針對整個context下的所有模組而言的,而不是單指某個模組,也就是說這個預設的7秒是指所有模組應該在7秒之內全部載入完成。7秒之後,如果有沒有被載入的模組,將拋出error指示哪些模組沒有載入。(requirejs每隔50毫秒做一次判斷)。

基準URL – baseUrl

每個context的基準URL預設值是”./”。

第一個context的基準URL

如果開發人員沒有指定context名稱,那麼這個第一個context就是requirejs預設產生的context,否則就是開發人員自己定義的context。在不指定基準URL的前提下,第一個context的基準URL設定比較特殊,除了標準的設定方法(參考後面的基準URL標準設定方法),還可以使用以下兩種特殊方式設定:

第一種:通過requirejs或require對象配置

在確認requirejs指令碼之前沒有其它requirejs執行過的前提下:

<script>requirejs={baseUrl: ‘./‘}</script>

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

<script>require={baseUrl: ‘./‘}</script>

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

注意:通過這種方式設定基準URL,data-main指定的指令檔位置也會變成相對於基準URL的路徑,因為data-main指定的指令碼本身只是依賴的關係之一。而且,data-main指定的指令碼也屬於第一個context。

比如下面這種情況:

<script>requirejs={baseUrl: ‘scripts/lib‘}</script>

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

指令碼模組app.js的最終路徑變成了"scripts/lib/scripts/app.js",不是原來的"scripts/app.js",而且它的依賴名稱也會變為scripts/lib/scripts/app(requirejs預設會去掉指令碼路徑的最後一個“.js”,除非data-main的值以“/”開頭,或包含“:”,或包含“?”)

第二種:根據script元素的data-main屬性指定的指令碼路徑計算

如果沒有設定baseUrl,requirejs會根據script元素data-main屬性指定的JavaScript檔案路徑計算出一個基準URL。

比如data-main="scripts/app.js",那麼baseUrl就是"scripts/":

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

基準URL標準設定方法

除了第一個context可以使用上面的方法,其它自訂的context配置baseUrl就只能使用下面這兩種方法。但這兩種方法同樣也可以用來修改第一個context的屬性,在不指定context名稱的情況下,其實就是修改第一個context

通過requirejs或require方法(這兩個本身就是同一個方法)設定

以下兩個等於把預設命名空間的基準URL設定成了scripts/lib:

requirejs({baseUrl:‘scripts/lib‘});

require({baseUrl:‘scripts/lib‘});

通過requirejs.config方法

requirejs.config({baseUrl:‘scripts/lib‘});

require.config({baseUrl:‘scripts/lib‘});

其實config方法調用的就是requirejs方法,所以它們是一樣的。

模組依賴 – deps

模組依賴是指個模組之間的相互依賴關係,指令碼運行時,只有當依賴的模組全部載入完成之後,當前指令碼才會執行,這就是依賴關係的作用。

依賴關係使用數組配置,數組元素為字串(即模組的名稱),一般是相對於baseUrl的路徑,只不過沒有檔案尾碼。而且,為了比較方便的擷取模組入口,模組一般會通過define方法定義。因為,通過define定義的模組,可以被依賴數組後面的回呼函數直接擷取並使用。

以jQuery為例,在jquery指令碼的末尾一般有下面兩行代碼:

if(typeof define === "function"&& define.amd && define.amd.jQuery) {

    define("jquery", [], function () { return jQuery; } );

}

再以underscore為例,在指令碼末尾有下面幾行代碼:

if (typeof define === ‘function‘ && define.amd) {

  define(‘underscore‘, [],function() {

    return _;

  });

}

模組和模組位置

使用require配置相依模組的時候,只是聲明了模組的名稱,卻不知道模組的具體位置。在沒有特殊聲明的情況下,requirejs認為模組名和檔案名稱相同,因此,只要兩者一致,requirejs就可以正確找到指令檔。但如果不同,就需要通過path配置:

requirejs.config({

    baseUrl:"scripts/lib",

    paths: {

        jquery:‘jquery-1.7.2‘

    }

});

這樣,requirejs就知道jquery模組位於scripts/lib/jquery-1.7.2.js檔案中。

第一個context的依賴關係

<script>requirejs={deps: [‘jquery‘]}</script>

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

其它context的依賴關係

與基準URL的方式一樣,既可以通過requirejs方法,也可通過requirejs.config方法配置。

模組束-bundles

如果一個JS檔案中有多個模組,就可以使用模組束的方式聲明:

requirejs.config({

    baseUrl:"scripts/lib",

    bundles: {

        jsUtil:[‘MathUtil‘, ‘DateUtil‘]

    }

});

上面這個例子就是說在scripts/lib/jsUtils.js檔案中有MathUtil和DateUtil這兩個子模組。

JS包– packages

如果一個檔案夾中有多個JS檔案,使用path的方式寫全就需要很多行代碼,這個時候如果使用包的方式聲明就可以省去很多麻煩:

requirejs.config({

    baseUrl:"scripts/lib",

    pkgs: [{name:‘jqueryui‘,location: ‘jqueryui/‘,main: ‘core‘}]

});

這樣定義之後,凡是在scripts/lib/jqueryui/目錄下的模組就可以通過這種方式正確找到:

require([‘jqueryui/button‘, ‘jqueryui/dialog‘]);

上面這個例子就是擷取scripts/lib/jqueryui/button.js和scripts/lib/jqueryui/dialog.js的例子。另外,因為jqueryui是一個目錄,並不對應一個JS檔案,所以又有一個main屬性,這個屬性一般對應這個JS包中的主程式檔案。上面的例子中,jqueryui的主程式就在scripts/lib/jqueryui/core.js中。

楔子 – shim

並不是所有的JS模組都會像jquery和underscore那樣調用define方法定義自己,這樣requirejs就不知道你這個模組的入口在哪,該通過哪個對象來調用這個模組,特別是那些早版本的JS模組,因為那是還沒有define和require的概念。

requirejs.config({

    baseUrl:"scripts/lib",

    shim: {jquery: {deps:[],exportsFn: func, exports:‘jQuery‘,init:func}}

});

雖然模組沒有使用define方法定義自己,但開發人員應該是知道如何擷取檔案中的模組的,所以,requirejs提供了兩種方式讓開發人員把模組對象返回給requirejs管理:

  • 在exportsFn或init方法中設定,然後作為傳回值;
  • 使用exports設定,比如”a.b.c”,那requirejs就知道通過window.a.b.c可以擷取。
映射 – Map

先來看問題:一些第三方JS外掛程式的依賴關係是事先設定好的,不太好修改相依模組的名稱,而如果某個模組有多個版本或有其他模組和它同名,則使用上面的配置都無法解決問題。比如path只是解決模組名稱到路徑的問題,而這個面對的是切換模組名稱的問題。於是requirejs提出了映射的概念,根據當前指令碼的名稱動態修改所相依模組的ID,是它指向正確的模組。

假如在你的硬碟下有以下幾個模組:

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

在newmodule.js和oldmodule.js中都有require(‘foo’)調用,要解決衝突只需要這樣配置即可:

requirejs.config({

    map: {

        ‘some/newmodule‘:{

            ‘foo‘: ‘foo1.2‘

        },

        ‘some/oldmodule‘:{

            ‘foo‘:‘foo1.0‘

        }

    }

});

主程式入口data-main

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

不管頁面上有多少個script元素有data-main屬性,requirejs只認最後一個script元素的data-main屬性,忽略其他script元素的data-main屬性。

Requirejs擷取data-main屬性之後,並沒有立即執行data-main指定的指令檔(因為這個指令檔可能還依賴了其他模組),而是把它作為了一個被依賴的模組,加入到第一個context的依賴數組中。比如下面這種情況就是把scripts/app這個模組加到一個名叫linus的context中:

<script type="text/javascript">

    requirejs={

        context: ‘linus‘,

        baseUrl:"./",

        skipDataMain: false

    };

</script>

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

全域配置忽略script元素的data-main

在瀏覽器中,有一個選項叫skipDataMain,可以讓requirejs忽略script元素的data-main。在預設情況下,requirejs成功載入之後,會立馬尋找頁面上所有script元素,並且把最後一個有data-main屬性的script元素的data-main最為主程式入口。

<script>requirejs={skipDataMain:true}</script>

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

模組定義 – define(name, deps, callback)

你會發現define方法沒有指定context名稱,這是因為define方法只調用於被依賴的模組中,而require方法已經為依賴的模組指定了context名稱,所以,這個模組被哪個context需要,它就屬於那一個context。

參數name是模組的名稱,deps是該模組所依賴的其他模組的名稱,callback一般返回該模組的實際可被使用對象。比如jQuery的模組定義回呼函數返回的就是jQuery對象。

Error載入Error

這種error就是瀏覽器內建的Error對象,只不過requirejs給它附加了其他屬性。

  • message的格式為:msg + ‘\nhttp://requirejs.org/docs/errors.html#‘ + id。
  • error.requireType就是就是message後面的id;
  • error.requireModules一般指需要載入卻沒載入成功的模組名稱;
  • error.originalError是指發生其他錯誤導致模組載入失敗的原始error對象。

Requirejs常用配置和應用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.