Knockoutjs是一個JavaScript實現的MVVM框架。主要有如下幾個功能:
1. Declarative bindings
2. Observables and dependency tracking
3. Templating
- 它對於分離前台的業務邏輯和視圖簡化數據綁定過程有顯著的作用。閑言少敘,直接看例子,如何下載也不說了,如果用VS開發的話用Nuget就可以一鍵搞定。
-
1. 基本綁定和依賴跟蹤
首先需要定義一個ViewModel:
<script type="text/javascript"> function ViewModel() { this.firstName = "Zixin"; this.lastName = "Yin"; } </script>
然后是一個用來顯示這個ViewModel的View:
<div> <p data-bind="text: firstName"></p> <p data-bind="text: firstName"></p> <input data-bind="value: firstName"/> <input data-bind="value: lastName"/> </div>
從這個view中可以看到聲明式綁定的含義,只需要在標簽上使用data-bind屬性,就可以將數據的值綁定到相應的地方。有了View和ViewModel還需要代碼將這兩者關聯起來:
ko.applyBindings(new ViewModel());
將他們放到一起,注意,applyBinding那代碼必須在頁面全部加載完之后執行。頁面顯示為:
下面再看observables,這個功能不是與生俱來的,必須要把View Model設置為observable,方法如下:
function ViewModel() { this.firstName = ko.observable("Zixin"); this.lastName = ko.observable("Yin"); }
其他都不需要改變,這時候,如果改變輸入框中的值,當焦點離開的時候,可以發現p中的值也跟着改變了:
下面再看dependency tracking,也就是如果一個值依賴多各值,其中任何一個值發生變化,它都會自動發生變化. 這是通過computed方法實現的,代碼如下:
function ViewModel() { this.firstName = ko.observable("Zixin"); this.lastName = ko.observable("Yin"); this.fullName = ko.computed(function () { return this.lastName() + " " + this.firstName(); },this); }
注意獲得一個observable的值是一個函數調用。這樣當first 或者last name發生變更的時候fullName也會自動跟着變更。
也可以通過代碼改變observable的值,頁面會自動刷新:
function ViewModel() { //……… this.capitalizeLastName = function () { this.lastName(this.lastName().toUpperCase()); } }
在頁面上添加一個按鈕:
<button data-bind="click: capitalizeLastName">Caps</button>
點擊按鈕之后便會出發viewmodel的capitalizeLastName方法,要改變一個observable的值的方法就是將新值作為函數調用的參數。點擊之后:
2. 列表綁定
加入我們有如下的訂單ViewModel,使用observableArray來跟蹤數組的變化。
var products=[{name:"Thinkpad X1",price:9000}, {name:"Hp ProBook",price:5555}, {name:"Mouse",price:45} ]; function Order() { var self = this; self.items = ko.observableArray([ //This data should load from server new Item(products[0], 1), new Item(products[1],2)]); self.price = ko.computed(function () { var p=0; for (var i = 0; i < self.items().length; i++) { var item = self.items()[i]; p += item.product.price * item.amount(); } return p; }, self); }
Order里面的Item實際上應該是從服務器獲得的,Item定義如下:
function Item(product, amount) { var self = this; this.product = product; this.amount = ko.observable(amount); this.subTotal = ko.computed(function () { return self.amount() * self.product.price; }, self); }
ViewModel准備好之后,就可以實現View。這次需要使用foreach綁定,如下:
<table> <thead> <tr> <td>Name</td> <td>Amount</td> <td>Price</td> </tr> </thead> <tbody data-bind="foreach: items"> <tr> <td data-bind="text: product.name"></td> <td><select data-bind="options:[1,2,3,4,5,6],value: amount"></select></td> <td data-bind="text: subTotal"></td> </tr> </tbody> </table> <h3>Order Price:<span data-bind="text: price"></span></h3>
這樣一個基本的訂單頁面就好了,能夠選擇數量,價格會自動更新:
下面給訂單加上增刪產品的功能,先給Order加上如下的方法:
function Order() { //…… self.remove = function (item) { self.items.remove(item); } self.addMouse = function () { self.items.push(new Item(products[2],1)); } }
給表格加上一列刪除按鈕:
<td><a href="#" data-bind="click: $root.remove">Remove</a></td>
再在表格底部加上一個增加產品的按鈕:
<button data-bind="click: addMouse">Add a Mouse</button>
這時候,observableArray的功能就體現了,當你點擊刪除按鈕或者底部的按鈕的時候,頁面節點會跟着變化,而不需要手動更新DOM節點,這使得前端的JS大大簡化。






