Knockout.js與MVVM模式簡介
本篇教學會教讀者使用knockout.js的Model-View-ViewModel(MVVM)模式建立網頁UI的基礎知識。
讀者將學習如何定義UI外觀使用Views和宣告式繫結(declarative bindings)。它的資料和行為使用ViewModels和observables,和如何一切都保持在同步中自動由Knockout.js的相依追蹤(dependency tracking)(即使有任意鏈結(chain)的資料)。
在View使用繫結
下面,擁有一個包含個人資料的ViewModel。
// 這是一個簡單的ViewModel物件 function AppViewModel() { this.firstName = "Bert"; this.lastName = "Bertington"; } // 啟用Activates knockout.js ko.applyBindings(new AppViewModel());
App物件包含兩個屬性,firstName與lastName。ko.applyBindings()是第一行knockout.js的程式碼,ko長knockout.js的關鍵字,applyBindings()方法是指定要繫結至那個ViewModel物件。
在View(專指呈現UI所在的地方,通常是指HTML)裡呈現個人資料,現在只呈現”todo”:
<!-- 這是View,HTML定義如何呈何UI --> <p>姓: <strong>todo</strong></p> <p>名: <strong>todo</strong></p>
修改View裡的<strong>元素,新增data-bind屬性來呈現個人名稱:
<p>姓: <strong data-bind="text: firstName"></strong></p> <p>名: <strong data-bind="text: lastName"></strong></p>
data-bind屬性讓Knockout.js可以讓你以宣告方式將DOM元素與ViewModel屬性產生關聯。使用text繫結分配文字給DOM元素。
就這樣,我們完成了第一個有View有ViewModel的knockout.js網頁。
讓資料可編輯
當然,我們不限於呈現靜態資料。我們可以使用value繫結以及一些HTML元素,例如,<input>元素,使資料可以編輯。在View裡新增以下標籤:
<p>姓: <input data-bind="value: firstName" /></p> <p>名: <input data-bind="value: lastName" /></p>
重新執行應用程式。我們已經可以編輯資料,編輯後沒有發生什麼事。當然,我們希望發生一些事…
簡介Observables
實際上,當你編輯這些文字時,它會更新ViewModel裡的資料,但是因為ViewModel的屬性只是純JavaScript字串(例如,this.firstName = "Bert";,"Bert"值是純字串),它們有沒有辦法通知任何人,他們改變了,所以UI保持靜態不變。這就是為什麼 Knockout.js具有observables(可觀察物件)的概念 — — 這些都是它們的值發生變動時,自動就會發出通知的屬性。
更新ViewModel,ko.observable()來觀察firstName與lastName屬性。
function AppViewModel() { // 純字串 // this.firstName = "Bert"; // this.lastName = "Bertington"; // 使用可觀察物件 this.firstName = ko.observable("Bert"); this.lastName = ko.observable("Bertington"); }
重新執行應用程式。當我們完成修改離開輸入框時,相關連結的UI項目也會同步被knockout.js更新。
合併與計算
經常,我們被要求合併或轉換多個觀察的屬性值。以下範例會定義一個fullName,fullName格式是「firstName + "空格" + lastName」,在knockout.js要處理這種情況可使用computed(計算)屬性,它也是可觀察物件,它的計算是基於其他可觀察物件的值。
新增fullName屬性到ViewModel,然後進行computed計算:
this.fullName = ko.computed(function() { return this.firstName() + " " + this.lastName(); }, this);
正如您所看到的,我們將回呼函數(callback function)傳遞給ko.computed指定它應該如何計算其值。下一步,呈現fullName值在你的UI裡:
<p>全名: <strong data-bind="text: fullName"></strong></p>
重新執行應用程式。當我們完成修改離開輸入框時,相關連結的UI項目(含fullName)也會同步被knockout.js更新。
如何運作
狀態能保持同步,是因為自動相依追蹤:最後一個<strong>相依於fullName,而fullName又相依於firstName和lastName,而fistName和lastName又可以通過編輯框來改變。任何的變更通過最小的物件關連變動來立即更新ViewModel與UI。
加入行為
我們為範例加上一個行為,設計一個按鈕,按鈕的內容可以讓姓和名變成全大寫。
首先加入一個uppercaseLastName方法到ViewModel裡,然後實作它:
this.uppercaseLastName = function() { var currentLastName = this.lastName(); // 讀取現值 this.lastName(currentLastName.toUpperCase()); // 寫入修改後的值 };
注意,讀取或寫入可觀察物件的值,必須當成函式呼叫。
下一步,新增一個<button>元素到View,使用click繫結來關聯click事件與ViewModel裡的函式:
<button data-bind="click: uppercaseLastName">轉換為大寫</button>
重新執行應用程式。點擊【轉換為大寫】,你可以看到UI會立即更新lastName的狀態為全大寫。
以下為完整程式碼。
<!DOCTYPE html> <html> <head> <title>Knockout.js與MVVM模式簡介</title> <script src="knockout-2.1.0.js"></script> <script> function AppViewModel() { // 純字串 // this.firstName = "Bert"; // this.lastName = "Bertington"; // 使用可觀察物件 this.firstName = ko.observable("Bert"); this.lastName = ko.observable("Bertington"); // 計算 this.fullName = ko.computed(function() { return this.firstName() + " " + this.lastName(); }, this); // 轉換大寫 this.uppercaseLastName = function() { var currentVal = this.lastName(); // 讀取現值 this.lastName(currentVal.toUpperCase()); // 寫入修改後的值 }; } ko.applyBindings(new AppViewModel()); </script> </head> <body> <p>姓: <strong data-bind="text: firstName"></strong></p> <p>名: <strong data-bind="text: lastName"></strong></p> <p>全名: <strong data-bind="text: fullName"></strong></p> <br /> <p>姓: <input data-bind="value: firstName" /></p> <p>名: <input data-bind="value: lastName" /></p> <button data-bind="click: uppercaseLastName">轉換為大寫</button> </body> </html>
黑大最近也發了蠻多knockout的文
回覆刪除兩位都有po文 這東西應該蠻有搞頭的
無法和黑大比,人家是有程度的文章,我只是…
刪除金剛兄,經實測發現使用您的完整程式碼會產生錯誤,無法運行。
回覆刪除第二個script,移到下面才OK。
給您參考。
以上
James
其實問題在 ko.applyBindings(new AppViewModel()); 因為是翻譯,所以就不異動它了。
刪除建議包在
$(function(){
ko.applyBindings(new AppViewModel());
});
等DOM元素都Ready後在進行Binding動作。