Knockout 新版應用開發教程之創建view models與監控屬性 章節導航 章節導航 最近抽出點時間研究MVVM,包括司徒正美的avalon,google的angular,以及Knockout,博客園Tom的Knockout指南 時隔2年了,ko更新了不少,所以文檔也相應的變化了,所以本人從 ...
Knockout 新版應用開發教程之創建view models與監控屬性
章節導航- 最近抽出點時間研究MVVM,包括司徒正美的avalon,google的angular,以及Knockout,博客園Tom的Knockout指南 時隔2年了,ko更新了不少,所以文檔也相應的變化了,所以本人從學習的角度就翻譯下官方的新的教程文章。
- avalon就是從KO演變過來的,不過加入ng,emberjs等框架的特色,加入許多巧妙的設計,算是很短小精悍的框架了,大家有興趣可以對比下。
Knockout是構建在3個核心的特性上的:
- 監控屬性(Observables)和依賴跟蹤(Dependency tracking)
- 聲明式綁定(Declarative bindings)
- 模版(Declarative bindings)
這一節,你講學到3個核心特性中的第一個。 在這之前, 我們來解釋一下MVVM模式和view model的概念。
MVVM and View Models 概念
模型-視圖-視圖模型(MVVM)是一種設計模式用來構建用戶界面,它描述瞭如何讓一個複雜的UI界面分解成3個部分:
- 模型:你應用存儲的數據.數據包括對象和業務操作(例如:銀子賬戶可以完成轉賬功能)並且獨立於任何的UI,使用KO的時候,通常說是向伺服器調用Ajax讀寫這個存儲的模型數據。
- 視圖模型:在UI上,純code描述的數據以及操作。例如,如果你實現列表編輯,你的view model應該是一個包含列表項items的對象和暴露的add/remove列表項(item)的操作方法。
註意這不是UI本身:它不包含任何按鈕的概念或者顯示風格。它也不是持續數據模型 – 包含用戶正在使用的未保存數據。使用KO的時候,你的view models是不包含任何HTML知識的純JavaScript 對象。保持view model抽象可以保持簡單,以便你能管理更複雜的行為。
- 視圖:一個可見的,互動式的,表示view model狀態的UI。 從view model顯示數據,發送命令到view model(例如:當用戶click按鈕的時候) ,任何view model狀態改變的時候更新
使用KO的時候,你的view就是你帶有綁定信息的HTML文檔,這些聲明式的綁定管理到你的view model上。或者你可以使用模板從你的view model獲取數據生成HTML。
例如:創建一個KO的view model,只需要聲明任意的JavaScript object,
2 3 4 5 |
var myViewModel = {
personName: 'Bob' ,
personAge: 123
};
|
你能創建一個非常簡單view model 用於聲明綁定.
例如: 下麵的代碼顯示personName 值
2 |
The name is <span data-bind= "text: personName" ></span>
|
激活Knockout
- data-bind 屬性不是HTML本身持有的,儘管它很好使用(它嚴格遵從HTML5語法, 雖然HTML4驗證器提示有不可識別的屬性但依然可用),但游覽器本身是不知道它是什麼意思的,你需要激活Knockout讓這個屬性生效
激活Knockout,需要添加如下的 <script> 代碼塊:
2 |
ko.applyBindings(myViewModel);
|
你可以把腳本塊放到你的HTML文檔的的底部,也可以放在頂部用jQuery的$函數載入
就這樣了!現在,如過你寫了下HTML代碼你的的視圖將顯示:
2 |
The name is <span>Bob</span>
|
你可能比較疑惑,ko.applyBindings使用了什麼參數?
- 第一個參數就是view model模型對象,你想要用來激活聲明綁定
- 可選參數,你能通過第二個參數來定義上下文,也就是說可以在指定的文檔範圍內查找 data-bind屬性
- 例如:
ko.applyBindings(myViewModel, document.getElementById('someElementId'))
- 它的現在是只有作為someElementId 的元素和子元素才能激活KO功能。 好處是你可以在同一個頁面聲明多個view model,用來區分區域。
真的,很簡單
Observables 監控屬性
好了,你已經看到瞭如何創建一個基本的view model 並且怎麼去顯示的去綁定它的屬性。
但是KO有一個核心的功能,當你的view model發生改變的時候它會自動更新你的UI。
當你的view model發現改變時怎麼才能讓KO知道呢?
回答:你需要把模型的屬性聲明稱監控屬性,因為它是非常特殊的javascript對象,能夠通知在改變的時候通知訂閱者,並且能夠自動偵測依賴。
例如:改寫以前一個view model對象:
2 3 4 5 |
var myViewModel = {
personName: ko.observable( 'Bob' ),
personAge: ko.observable(123)
};
|
你不必改變所有的視圖 - 這些 data-bind 的語法繼續保持工作。不同的地方是它能夠檢測到改變,並且當使用的時候,它將會自動更新view.
Reading and writing observables 監控屬性的讀和寫
不是所有的游覽器都支持JavaScript getters 和 setter(* cough * IE * cough *),所以為了相容,ko.observable 對象實際上一個 functions.
- 讀監控屬性當前的值,直接調用不需要參數。
- 例如:
myViewModel.personName()
will return'Bob'
, andmyViewModel.personAge()
will return123
.- 寫一個新的值到監控屬性,調用監控屬性並且傳入一個新的值作為一個參數。
- 例如:
myViewModel.personName('Mary')
將把值變成'Mary'。- 在一個model對象中寫一個值到多個監控屬性,你將能用到鏈式 語法。
- 例如:
- myViewModel.personName('Mary').personAge(50)
- 將把name的值變'Mary'並且age的值變成50.
- observables的意義就是能夠被監控(observed),i.e, 其他代碼可以這樣說,它想要更改的通知。所以KO內部有很多內置的綁定語法。所以,當你寫
data-bind="text: personName",
這個text會註冊綁定它自己被通知改變,當personName的值改變,它就能得到通知(假設這是一個可以observable的值)。
當你用myViewModel.personName('Mary')改變這個name值是value = ’Mary’時,text綁定將自動更新這個新值到相應的DOM元素上,這就是如何改變視圖模型自動傳播到視圖的。
Explicitly subscribing to observables 顯式訂閱監控屬性
通常來說如果你不需要手動的去設置訂閱,那麼你可以跳過這一節。
對於高級用戶,假如你想註冊自己的訂閱通知的變化來觀察,你能夠調用它的subscribe方法,例如
2 3 4 |
myViewModel.personName.subscribe( function (newValue) {
alert( "The person's new name is " + newValue);
});
|
subscribe 方法在KO內部許多地方都被使用。大部分時間你都不需要用它,因為它是內置綁定並且是由模版系統管理訂閱。
subscribe 有三個參數:
callback 回調函數,當發生的通知調用
target(可選)定義在回調函數中的this
event(可選默change—)接收通知的事件的名稱
你也可以終止自己的訂閱:首先得到你的訂閱,然後調用這個對象的dispose函數,例如:
2 3 4 |
var subscription = myViewModel.personName.subscribe( function (newValue) { /* do stuff */ });
// ...then later...
subscription.dispose(); // I no longer want notifications
|
如果你想被通知以前被監控的值,它被改變,你可以訂閱的beforechange事件:
2 3 4 |
myViewModel.personName.subscribe( function (oldValue) {
alert( "The person's previous name is " + oldValue);
}, null , "beforeChange" );
|
Forcing observables to always notify subscribers
當寫一個了監控屬性,它包含一個原始值時,如果dependencies依賴的observable正常情況下只會有value發生改變才會通知。然而,可以使用內置的通知extender確保observable’s的訂閱在寫的時候總是會發出通知,即使值是相同的。你會運用extender到一個監控屬性中:
2 |
myViewModel.personName.extend({ notify: 'always' });
|