文章出處

組件綁定將指定的組件注入到元素中,并且可選地將參數傳遞給它。

本節目錄

  • 一個例子
  • API
  • 組件生命周期
  • 備注1:僅限模板組件
  • 備注2:使用沒有容器元素的組件
  • 備注3:將標記傳遞給組件
  • 處置和內存管理

一個例子

First instance, without parameters

Second instance, passing parameters

UI源碼:

<h4>First instance, without parameters</h4>
<div data-bind='component: "message-editor"'></div>
 
<h4>Second instance, passing parameters</h4>
<div data-bind='component: {
    name: "message-editor",
    params: { initialText: "Hello, world!" }
}'>
</div>

視圖模型源碼:

ko.components.register('message-editor', {
    viewModel: function(params) {
        this.text = ko.observable(params && params.initialText || '');
    },
    template: 'Message: <input data-bind="value: text" /> '
            + '(length: <span data-bind="text: text().length"></span>)'
});
 
ko.applyBindings();

注意:在更現實的情況下,通常從外部文件加載組件視圖模型和模板,而不是將它們硬編碼到注冊中。

API

有兩種方法使用組件綁定:

快速語法:

如果你只傳遞一個字符串,它被解釋為一個組件名稱。 然后注入命名的組件,而不向其提供任何參數。 例:

<div data-bind='component: "my-component"'></div>

也可以將監控屬性作為組件名稱。 在這種情況下,如果監控屬性值更改,組件綁定將處理舊組件實例,并注入新引用的組件。 例:

<div data-bind='component: observableWhoseValueIsAComponentName'></div>

完整語法:

要向組件提供參數,請傳遞具有以下屬性的對象:

  • name — 要注入的組件的名稱。 同樣,這可以是監控屬性。
  • params —將被傳遞給組件的對象。 通常,這是一個包含多個參數的鍵值對象,通常由組件的viewmodel構造函數接收。

例如:

<div data-bind='component: {
    name: "shopping-cart",
    params: { mode: "detailed-list", items: productsList }
}'>
</div>

組件生命周期

當組件綁定注入組件時,

  1. 請求您的組件加載器提供viewmodel工廠和模板

    • 可以查閱多個組件加載器,直到第一個識別組件名稱并提供視圖模型/模板。 此過程僅對每個組件類型發生一次,因為Knockout在內存中緩存生成的定義。
    • 默認組件加載器根據您注冊的內容提供viewmodels /template。 如果適用,這是從AMD加載器請求任何指定的AMD模塊的階段。
  2. 通常,這是一個異步過程。 它可能涉及對服務器的請求。 對于API一致性,Knockout默認確保加載過程作為異步回調完成,即使組件已經加載并緩存在內存中。 有關更多信息以及如何允許同步加載,請參閱上一節的控制同步/異步加載。

  3. 組件模板被克隆并注入到容器元素中

    任何現有內容都將被刪除并丟棄。

  4. 如果組件有一個viewmodel,它被實例化

    如果viewmodel是作為構造函數給出的,這意味著Knockout調用新的YourViewModel(params)。

    如果viewmodel作為createViewModel工廠函數給出,Knockout callscreateViewModel(params,componentInfo),其中componentInfo.element是尚未綁定的未綁定模板的元素。

    這個階段總是同步完成(構造函數和工廠函數不允許是異步的),因為每次組件被實例化時都會出現這種情況,如果涉及等待網絡請求,性能將是不可接受的。

  5. viewmodel被綁定到視圖

    如果組件沒有viewmodel,則視圖將綁定到您提供給組件綁定的任何參數。

  6. 組件處于活動狀態

    現在組件正在運行,并且可以在需要時保持在屏幕上。

    如果傳遞給組件的任何參數是監控屬性,則組件當然可以觀察到任何改變,或者甚至回寫修改的值。 這是它如何能夠干凈地與其父進行通信,而不是將組件代碼緊密地耦合到使用它的任何父進程。

  7. 組件被拆卸,并且視圖模型被刪除

    If如果組件綁定的名稱值可觀察地改變,或者如果封閉的控制流綁定導致容器元素被移除,則在從DOM移除容器元素之前調用視圖模型上的任何dispose函數。 參見本節:處置和內存管理。

    注意:如果用戶導航到完全不同的網頁,瀏覽器會執行此操作,而不會要求頁面中運行的任何代碼進行清理。 所以在這種情況下不會調用dispose函數。 這是正常的,因為瀏覽器會自動釋放所有使用的對象使用的內存。

 

備注1:僅限模板組件

組件通常有viewmodels,但它們不一定必須。 組件只能指定一個模板。

在這種情況下,組件視圖所綁定的對象是您傳遞給組件綁定的params對象。 例:

ko.components.register('special-offer', {
    template: '<div class="offer-box" data-bind="text: productName"></div>'
});

...可以注入參數:

<div data-bind='component: {
     name: "special-offer-callout",
     params: { productName: someProduct.name }
}'></div>

或者,更方便地,作為自定義元素:

<special-offer params='productName: someProduct.name'></special-offer>

備注2:使用沒有容器元素的組件

有時,您可能想要將一個組件注入到視圖中,而不使用額外的容器元素。 您可以使用基于注釋標簽的無容器控制流語法。 例如,

<!-- ko component: "message-editor" -->
<!-- /ko -->

...或傳遞參數:

<!-- ko component: {
    name: "message-editor",
    params: { initialText: "Hello, world!", otherParam: 123 }
} -->
<!-- /ko -->

<!-- ko -- >和<!-- / ko -- >注釋作為開始/結束標記,定義一個包含標記的“虛擬元素”。 Knockout理解這個虛擬元素的語法,并綁定,就像你有一個真正的容器元素。

備注3:將標記傳遞給組件

您附加組件綁定的元素可能包含進一步的標記。 例如,

<div data-bind="component: { name: 'my-special-list', params: { items: someArrayOfPeople } }">
    <!-- Look, here's some arbitrary markup. By default it gets stripped out
         and is replaced by the component output. -->
    The person <em data-bind="text: name"></em>
    is <em data-bind="text: age"></em> years old.
</div>

雖然此元素中的DOM節點將被刪除,并且不會默認綁定,但它們不會丟失。 相反,它們被提供給組件(在這種情況下,my-special-list),它可以將它們包括在它希望的輸出中。

如果要構建表示“容器”UI元素的組件(如網格,列表,對話框或標簽集),這需要注入并將任意標記綁定到公共結構中,這將非常有用。 它也可以在沒有自定義元素的情況下使用上面顯示的語法。

處置和內存管理

您的viewmodel類可能具有dispose函數。 如果實現了,當組件被刪除并從DOM中刪除時,Knockout會調用它(例如,因為相應的項從foreach中刪除,或者如果綁定變為false)。

您必須使用dispose釋放任何本質上不可回收的資源。 例如:

  • setInterval 回調將繼續觸發,直到顯式清除。
    • 使用clearInterval(handle)來停止它們,否則你的viewmodel可能被保存在內存中。
  • ko.computed屬性繼續從其依賴關系接收通知,直到明確處置。
    • 如果一個依賴是一個外部對象,那么一定要使用.dispose()在computed屬性,否則它(可能還有你的viewmodel)將被保存在內存中。 或者,考慮使用pureComputed以避免手工處置的需要。
  • 監控屬性訂閱將繼續運行,直到明確被處理。
    • 如果你訂閱了一個外部的observable,一定要使用.dispose()在訂閱,否則回調(可能還有你的viewmodel)將被保存在內存中。
  • 外部DOM元素上手動創建的事件處理程序(如果在createViewModelfunction中創建)(甚至在常規組件視圖模型內部,盡管適合您不應該使用的MVVM模式)必須刪除。
    • 當然,您不必擔心在視圖中釋放由標準Knockout綁定創建的任何事件處理程序,因為KO會在刪除元素時自動注銷它們。

例如:

var someExternalObservable = ko.observable(123);
 
function SomeComponentViewModel() {
    this.myComputed = ko.computed(function() {
        return someExternalObservable() + 1;
    }, this);
 
    this.myPureComputed = ko.pureComputed(function() {
        return someExternalObservable() + 2;
    }, this);
 
    this.mySubscription = someExternalObservable.subscribe(function(val) {
        console.log('The external observable changed to ' + val);
    }, this);
 
    this.myIntervalHandle = window.setInterval(function() {
        console.log('Another second passed, and the component is still alive.');
    }, 1000);
}
 
SomeComponentViewModel.prototype.dispose = function() {
    this.myComputed.dispose();
    this.mySubscription.dispose();
    window.clearInterval(this.myIntervalHandle);
    // this.myPureComputed doesn't need to be manually disposed.
}
 
ko.components.register('your-component-name', {
    viewModel: SomeComponentViewModel,
    template: 'some template'
});

不必嚴格地需要僅僅依賴于相同viewmodel對象的屬性來處理計算和訂閱,因為這僅創建了JavaScript垃圾收集器知道如何釋放的循環引用。 然而,為了避免不必記住哪些事情需要處理,你可能更喜歡在任何可能的地方使用pureComputed,并且顯式地處置所有其他計算/訂閱,無論技術上是否必要。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()