(Knockout版本:3.4.1 )
KO的組件主要從以下四個部分進行詳細介紹:
1.組件的定義和注冊
2.組件綁定
3.使用自定義元素
4.自定義組件加載器(高級)
目錄結構
1.通過"視圖模型"、"模版"配對注冊組件
--1.1 指定視圖模型的方法
----1.1.1 構造函數
----1.1.2 對象實例
----1.1.3 創造視圖模型的工廠函數
----1.1.4 AMD模塊,其值描述了一個視圖模型
--1.2 指定模版的方法
----1.2.1 已存在元素的ID
----1.2.2 已存在元素的實例
----1.2.3 HTML字符串
----1.2.4 包含許多DOM節點的數組
----1.2.5 文檔片段
----1.2.6 AMD模塊,其值描述了一個模版
2.Knockout怎樣通過AMD加載組件
--2.1 AMD模塊為按需加載
3.通過一個AMD模塊注冊組件
--3.1 推薦的AMD組件模塊的定義方式
1.1.1 構造函數
function SomeComponentViewModel(params) {
// 'params' is an object whose key/value pairs are the parameters
// passed from the component binding or custom element.
this.someProperty = params.something;
}
SomeComponentViewModel.prototype.doSomething = function() { ... };
ko.components.register('my-component', {
viewModel: SomeComponentViewModel,
template: ...
});
Knockout將會調用這個構造函數並生成一個實例作為視圖模型,其中params參數在組件調用的時候傳入。
1.1.2 對象實例
直接傳遞一個對象實例作為視圖模型,所有使用這個對象的組件共享這一個實例。假定對象實例為modelInstance,注意傳入方法為:viewModel: {instance: modelInstance}
1.1.3 創造視圖模型的工廠函數
如果創建這個視圖模型需要取得一些組件調用的信息,那么就采取這從模式定義視圖模型。
ko.components.register('my-component', {
viewModel: {
createViewModel: function(params, componentInfo) {
// - 'params'是組件調用時傳入的對象
// - 'componentInfo.element'是組件注入的元素,當createViewModel方
// 法被調用時,組件已被注入到元素中,但還沒有發生綁定。
// - 'componentInfo.templateNodes'是一個包含了組件調用時內部的DOM節
// 點的數組。
// 通過自己定義的構造函數返回一個實例
return new MyViewModel(params);
}
},
template: ...
});
注意,操作DOM最好只通過自定義綁定,而不要通過componentInfo.element進行一些操作DOM的行為。
componentInfo.templateNodes在我們需要控制組件輸出的節點時會起到作用。
1.1.4 通過AMD模塊
如果使用了AMD模塊加載器,比如(require.js),可以使用模塊加載器直接加載AMD模塊作為視圖模型。
ko.components.register('my-component', {
viewModel: { require: 'some/module/name' },
template: ...
});
加載的AMD模塊只要按照1.1.1,1.1.2,1.1.3三種方式中的一種提供模塊(即returns)就可以了。另外還有一種一般不會用到的方式AMD模塊的return為 return { module: 'some/other/module' }
,這種方式將會加載其它模塊。
1.2.1 已存在元素的ID
<template id='my-component-template'>
<h1 data-bind='text: title'></h1>
<button data-bind='click: doSomething'>Click me right now</button>
</template>
ko.components.register('my-component', {
template: { element: 'my-component-template' },
viewModel: ...
});
指定一個已存在元素的ID即可,ID所對應元素本身不會被作為模版的元素傳入,其內部節點會作為模版被傳入。推薦使用例子里的< template>標簽,別的標簽也可以,但瀏覽器不識別template標簽所以它不會被渲染收到影響,另外語義也比較清晰。
1.2.2 已存在元素的實例
類似於傳入ID,只是這次傳入的是元素實例。
1.2.3 HTML字符串
ko.components.register('my-component', {
template: '<h1 data-bind="text: title"></h1>\
<button data-bind="click: doSomething">Clickety</button>',
viewModel: ...
});
當我們從別處取得一些字符串來生成模版時(比如AMD),這個方法很有用。
1.2.4 包含許多DOM節點的數組
var myNodes = [
document.getElementById('first-node'),
document.getElementById('second-node'),
document.getElementById('third-node')
];
ko.components.register('my-component', {
template: myNodes,
viewModel: ...
});
這些節點會依次作為組件模版被復制渲染出來。
1.2.5 文檔片段
1.2.6 AMD模塊
可以傳一個AMD模塊,這個模塊的返回值是以上模版的任一種類型都可以。
2.Knockout怎樣通過AMD加載組件
當為視圖模型和模版傳入require聲明時:
ko.components.register('my-component', {
viewModel: { require: 'some/module/name' },
template: { require: 'text!some-template.html' }
});
這些AMD模塊被加載,實際上類似於使用了require(['some/module/name'], callback)
和require(['text!some-template.html'], callback)
。KO加載這些模塊有三個需要注意的點:
*KO並不嚴格要求使用require.js,任何其它的AMD模塊加載器都可以使用。
*KO並不影響加載模塊的路徑,路徑仍然完全由所用的AMD加載器決定。
*KO並不關心所加載的模塊是否是暴露了全局變量名稱的模塊。
2.1 AMD模塊為按需加載
比如一個組件寫在了一個綁定了if指令的標簽中,那只有if對應的值真,組件模塊才加載,否則不加載。如果組件模塊已經加載過了, 那么將不再發送HTTP請求來請求模塊,而是預加載之前存下來的模塊。
3.1 推薦的AMD組件模塊的定義方式
只要AMD模塊返回的是以上任意一種合法的模塊配置就可以作為一個有效的組件模塊,但是有一種推薦的組件模塊定義方法:
// - 使用這種模式定義模塊的優點在於
// - 引入只需要一個require聲明
// - 可以被require.js的r.js打包
define(['knockout', 'text!./my-component.html'], function(ko, htmlString) {
function MyComponentViewModel(params) {
// 在這里設置屬性等
}
// 使用原型定義公共方法
MyComponentViewModel.prototype.doSomething = function() { ... };
// 返回組件的定義
return { viewModel: MyComponentViewModel, template: htmlString };
});
這樣定義的組件模塊,調用方法為:ko.components.register('my-component', { require: 'path/my-component' });
。一個組件模塊由兩個文件組成,一個視圖模型(path/my-component.js)和一個模版(path/my-component.html),創建自然,維護方便。