無論何時使用組件綁定或自定義元素注入組件,Knockout都將使用一個或多個組件裝載器獲取該組件的模板和視圖模型。 組件加載器的任務是異步提供任何給定組件名稱的模板/視圖模型對。
本節目錄
- 默認組件加載器
- 組件加載器實用函數
- 實現自定義組件加載器
- 可以實現的功能
getConfig(name, callback)
loadComponent(name, componentConfig, callback)
loadTemplate(name, templateConfig, callback)
loadViewModel(name, templateConfig, callback)
- 可以實現的功能
默認組件加載器
內置的默認組件加載器ko.components.defaultLoader基于組件定義的中心“注冊表”。 它依賴于您明確注冊每個組件的配置,然后才能使用該組件。
可參考第六章第一節。
組件加載器實用函數
以下函數讀取和寫入默認組件加載器的注冊表:
ko.components.register(name, configuration)
- 注冊組件
ko.components.isRegistered(name)
- 如果具有指定名稱的組件已注冊,則返回true;否則為假。
ko.components.unregister(name)
- 從注冊表中刪除指定的組件。或者如果沒有注冊這樣的組件,什么都不做。
以下函數在注冊的組件加載器的完整列表中工作(不僅是默認加載器):
ko.components.get(name, callback)
- 依次查詢每個注冊的加載器(默認情況下,只是默認加載器),找到第一個為命名的組件提供viewmodel /模板定義,然后調用回調來返回比viewmodel / template聲明。如果沒有注冊的裝載器知道這個組件,則調用回調(null)。
ko.components.clearCachedDefinition(name)
- 通常,Knockout對每個組件名稱查詢加載器一次,然后緩存生成的定義。這確保了可以非常快速地實例化大量組件。如果要清除給定組件的緩存條目,請調用此方法,然后在下次需要該組件時再次查詢加載程序。
此外,由于ko.components.defaultLoader是組件加載器,它實現以下標準組件加載器函數。您可以直接調用這些方法,例如,作為自定義加載器實施的一部分:
ko.components.defaultLoader.getConfig(name, callback)
ko.components.defaultLoader.loadComponent(name, componentConfig, callback)
ko.components.defaultLoader.loadTemplate(name, templateConfig, callback)
ko.components.defaultLoader.loadViewModel(name, viewModelConfig, callback)
實現自定義組件加載器
如果要使用命名約定而不是顯式注冊來加載組件,則可能需要實現自定義組件加載器。 或者,如果您想使用第三方“加載器”庫從外部位置獲取組件視圖模型或模板。
可以實現的功能
自定義組件加載器只是一個對象,其屬性是以下函數的任意組合:
getConfig(name, callback)
定義如下: 您希望基于名稱以編程方式提供配置,例如,實現命名約定。
如果聲明,Knockout將調用此函數為每個正在被實例化的組件獲取一個配置對象。
- 要提供配置,請調用回調(componentConfig),其中componentConfig是加載器或任何其他加載器上的loadComponent函數可以理解的任何對象。 默認加載器只提供使用ko.components.register注冊的任何對象。
- 例如,一個componentConfig像{template:'someElementId',viewModel:{require:'myModule'}}可以被默認加載器理解和實例化。
- 您不限于以任何標準格式提供配置對象。 只要loadComponent函數理解它們,就可以提供任意對象。
- 如果你不希望你的加載器提供一個命名組件的配置,那么callcallback(null)。 然后,Knockout將按順序查詢任何其他注冊的裝載器,直到提供非空值。
loadComponent(name, componentConfig, callback)
定義如下: 您想要控制組件配置的解釋方式,例如,如果您不想使用標準的viewModel /模板對格式。
如果聲明,Knockout將調用此函數將componentConfig對象轉換為viewmodel /模板對。
-
要提供一個viewmodel /模板對,請調用callback(result),其中result是具有以下屬性的對象:
template
- 必需。 DOM節點數組createViewModel(params, componentInfo)
- 可選。 稍后將調用的函數以為此組件的每個實例提供一個viewmodel對象
如果你不希望你的加載器為給定的參數提供一個viewmodel /模板對,那么callcallback(null)。 然后,Knockout將按順序查詢任何其他注冊的裝載器,直到提供非空值。
loadTemplate(name, templateConfig, callback)
定義如下: 您想要使用自定義邏輯為給定模板配置提供DOM節點(例如,使用ajax請求通過URL提取模板)。
默認組件加載器將在聲明它的任何注冊加載器上調用此函數,將組件配置的template部分轉換為DOM節點數組。 然后,為組件的每個實例緩存和克隆節點。
templateConfig值只是來自任何componentConfig對象的template屬性。 例如,它可能包含“some markup”或{element:“someId”}或自定義格式,如{loadFromUrl:“someUrl.html”}。
-
要提供DOM節點的數組,請調用回調(domNodeArray)。
-
如果您不希望您的加載程序為給定的參數提供模板(例如,因為它不能識別配置格式),請調用callback(null)。 然后,Knockout將按順序查詢任何其他注冊的裝載器,直到提供非空值。
loadViewModel(name, templateConfig, callback)
定義如下: 您想要使用自定義邏輯為給定的viewmodel配置(例如,與第三方模塊加載器或依賴注入系統集成)提供viewmodel工廠。
默認組件加載器將在聲明它的任何注冊加載器上調用此函數,將組件配置的viewModel部分轉換為createViewModel工廠函數。 然后,該函數被緩存,并為需要viewmodel的組件的每個新實例調用。
viewModelConfig值只是來自任何componentConfig對象的viewModel屬性。 例如,它可以是構造函數,或自定義格式,如{myViewModelType:'Something',options:{}}。
-
要提供一個createViewModel函數,請調用回調(yourCreateViewModelFunction)。 ThecreateViewModel函數必須接受參數(params,componentInfo),并且必須在每次調用時同步返回一個新的viewmodel實例。
-
如果你不希望你的加載器為給定的參數提供一個createViewModel函數(例如,因為它不能識別配置格式),call callback(null)。 然后,Knockout將按順序查詢任何其他注冊的裝載器,直到提供非空值。
注冊自定義組件加載器
Knockout允許您同時使用多個組件加載器。 這是有用的,例如,您可以插入實現不同機制的加載器(例如,可以根據命名約定從后端服務器獲取模板;另一個可以使用依賴注入系統設置視圖模型)并使它們工作 一起。
因此,ko.components.loaders是一個包含當前啟用的所有加載器的數組。 默認情況下,此數組只包含一個項目:ko.components.defaultLoader。 要添加額外的裝載器,只需將它們插入到ko.components.loaders數組中。
控制優先級
如果希望自定義加載器優先于默認加載器(因此它獲得第一次提供配置/值的機會),然后將其添加到數組的開頭。 如果您希望默認加載器優先(因此您的自定義加載器僅為未顯式注冊的組件調用),然后將其添加到數組的末尾。
例:
// Adds myLowPriorityLoader to the end of the loaders array. // It runs after other loaders, only if none of them returned a value. ko.components.loaders.push(myLowPriorityLoader); // Adds myHighPriorityLoader to the beginning of the loaders array. // It runs before other loaders, getting the first chance to return values. ko.components.loaders.unshift(myHighPriorityLoader)
如果需要,您可以從裝載器數組中刪除ko.components.defaultLoader。
調用順序
第一次Knockout需要構造一個具有給定名稱的組件,它:
- 依次調用每個注冊的裝載器的getConfig函數,直到第一個提供非nullcomponentConfig。
- 然后,使用此componentConfig對象,依次調用每個注冊的裝載程序的loadComponent函數,直到第一個提供非空模板/ createViewModel對。
當默認加載器的loadComponent運行時,它同時:
- 依次調用每個注冊的裝載器的loadTemplate函數,直到第一個提供非空的DOM數組。
- 默認加載器本身有一個loadTemplate函數,它將一系列模板配置格式解析為DOM數組。
- 依次調用每個注冊的裝載器的loadViewModel函數,直到第一個提供非空的createViewModel函數。
- 默認加載器本身有一個loadViewModel函數,它將一系列viewmodel配置格式解析為createViewModel函數。
自定義加載器可以插入此過程的任何部分,因此您可以控制提供配置,解釋配置,提供DOM節點或提供viewmodel工廠函數。通過將自定義加載器放入ko.components.loaders中的選定順序,您可以控制不同加載策略的優先級順序。
示例1:設置命名約定的組件加載程序
要實現命名約定,您的自定義組件加載器只需要實現getConfig。 例如:
var namingConventionLoader = { getConfig: function(name, callback) { // 1. Viewmodels are classes corresponding to the component name. // e.g., my-component maps to MyApp.MyComponentViewModel // 2. Templates are in elements whose ID is the component name // plus '-template'. var viewModelConfig = MyApp[toPascalCase(name) + 'ViewModel'], templateConfig = { element: name + '-template' }; callback({ viewModel: viewModelConfig, template: templateConfig }); } }; function toPascalCase(dasherized) { return dasherized.replace(/(^|-)([a-z])/g, function (g, m1, m2) { return m2.toUpperCase(); }); } // Register it. Make it take priority over the default loader. ko.components.loaders.unshift(namingConventionLoader);
現在已注冊,您可以使用任何名稱引用組件(無需預先注冊它們),例如:
<div data-bind="component: 'my-component'"></div> <!-- Declare template --> <template id='my-component-template'>Hello World!</template> <script> // Declare viewmodel window.MyApp = window.MyApp || {}; MyApp.MyComponentViewModel = function(params) { // ... } </script>
示例2:使用自定義代碼加載外部文件的組件加載器
如果您的自定義加載器實現了loadTemplate和/或loadViewModel,那么您可以在加載過程中插入自定義代碼。 您還可以使用這些函數來解釋自定義配置格式。
例如,您可能需要啟用以下配置格式:
ko.components.register('my-component', { template: { fromUrl: 'file.html', maxCacheAge: 1234 }, viewModel: { viaLoader: '/path/myvm.js' } });
...你可以使用自定義加載器。
以下自定義加載器將處理使用fromUrl值配置的加載模板:
var templateFromUrlLoader = { loadTemplate: function(name, templateConfig, callback) { if (templateConfig.fromUrl) { // Uses jQuery's ajax facility to load the markup from a file var fullUrl = '/templates/' + templateConfig.fromUrl + '?cacheAge=' + templateConfig.maxCacheAge; $.get(fullUrl, function(markupString) { // We need an array of DOM nodes, not a string. // We can use the default loader to convert to the // required format. ko.components.defaultLoader.loadTemplate(name, markupString, callback); }); } else { // Unrecognized config format. Let another loader handle it. callback(null); } } }; // Register it ko.components.loaders.unshift(templateFromUrlLoader);
...并且以下自定義加載器將負責加載使用簽名加載器值配置的視圖模型:
var viewModelCustomLoader = { loadViewModel: function(name, viewModelConfig, callback) { if (viewModelConfig.viaLoader) { // You could use arbitrary logic, e.g., a third-party // code loader, to asynchronously supply the constructor. // For this example, just use a hard-coded constructor function. var viewModelConstructor = function(params) { this.prop1 = 123; }; // We need a createViewModel function, not a plain constructor. // We can use the default loader to convert to the // required format. ko.components.defaultLoader.loadViewModel(name, viewModelConstructor, callback); } else { // Unrecognized config format. Let another loader handle it. callback(null); } } }; // Register it ko.components.loaders.unshift(viewModelCustomLoader);
如果你愿意,你可以將templateFromUrlLoader和viewModelCustomLoader結合到單個加載器中,方法是將loadTemplate和loadViewModel函數放在單個對象上。 然而,分離出這些問題是相當不錯的,因為它們的實現是相當獨立的。
注意1:自定義組件加載器和自定義元素
如果使用組件加載器通過命名約定獲取組件,并且不使用ko.components.register注冊組件,那么這些組件不會自動用作自定義元素(因為您還沒告訴Knockout他們存在)。
請參閱:第六章 組件(4) 自定義元素
注意2:與browserify集成
Browserify是一個流行的庫,用于以Node樣式的同步require語法引用JavaScript庫。它通常被認為是替代AMD加載器,如require.js。然而,Browserify解決了一個相當不同的問題:同步構建時參考解析,而不是由AMD處理的異步運行時參考解析。
因為Browserify是一個構建時間工具,它不需要真正需要與KO組件的任何特殊集成,并且沒有必要實現任何類型的自定義組件加載器來使用它。您可以簡單地使用Browserify的require語句來抓取您的組件視圖模型的實例,然后顯式地注冊它們,例如:
// Note that the following *only* works with Browserify - not with require.js, // since it relies on require() returning synchronously. ko.components.register('my-browserify-component', { viewModel: require('myViewModel'), template: require('fs').readFileSync(__dirname + '/my-template.html', 'utf8') });
這使用brfs Browserify插件自動內聯.html文件,因此您需要使用類似于以下命令構建腳本文件:
npm install brfs
browserify -t brfs main.js > bundle.js
章節結語
至此,KnockoutJS的組件介紹完畢,未來章節將介紹一些Knockout的其他技術。感謝你的閱讀,希望我的這個KnockoutJS系列能夠幫助到你,如果覺著文章不錯,請點一波推薦,歡迎留言,轉載請注明出處,http://www.cnblogs.com/smallprogram。謝謝
文章列表