之前曾過寫稍微寫過Flex,對於它在資料和元件之間的data binding設計,印象非常深刻。它既能從UI元件上更動,去變更資料,也能在資料變更時,即時反應到UI上。這樣雙向的互動,簡化不少元件互動上的coding功夫。
今天要來介紹的Knockout.js,就是能透過JavaScript來做到這件事
在進入Knockout.js細節之前,就讓我們先從範例來理解。
讓我們先從一個簡化的報名系統開始好了。
UI大致如下圖:
使用者只要點了「我要報名」,人數的統計就會累加上去。
這個報名系統的HTML如下:
<div id="register">
<h1>報名系統</h1>
<div>目前有<strong>0</strong>人報名</div>
<button>我要報名</button>
</div>
[jQuery vs Knockout.js作法比一比]
依照jQuery最直覺的作法,可能是:
1.取得報名人數的DOM
2.綁定button的click事件,在點擊時把人數加1,然後再把數字塞回DOM裡面
寫法大概就是這樣:
var counter = $('#register div strong');
$('#register button').click(function(){
var counterValue = counter.text();
counter.text(++counterValue);
});
那麼換作Knockout.js要怎麼做呢?
首先它必須要在綁定的HTML上,加上data-bind的標記,告訴Knockout.js資料要繫連的方式以及和它對應的資料,就像下面的做法:
<div id="register">
<h1>報名系統</h1>
<div>目前有<strong data-bind="text:counter">0</strong>人報名</div>
<button data-bind="click:increase">我要報名</button>
</div>
接下來,就換Knockout.js登場了。它的思維是,建立一個ViewModel物件,讓Knockout.js去綁定這個ViewModel,之後的工作,就全部交由Knockout.js來處理了。
我們先來看程式碼:
function CounterViewModel() {
this.counter = ko.observable(0);
this.increase = function() {
var counterValue = this.counter();
this.counter(++counterValue);
};
}
ko.applyBindings(new CounterViewModel());
我們先建立一個CounterViewModel的建構式函式作為ViewModel物件,這個物件中,包含了一屬性、一個方法。this.counter用來記錄counter值,而this.increase方法,則是用來處理按鈕按下時,為counter數加1。
在這裡我們看到第一個陌生的方法:ko.observable(),簡單地說,Knockout.js知道值改變並自動去更新,靠的就是透過ko.observable()來監看值的動態。因為要綁定的值,必須把它當作ko.observable()的參數傳入,然後再指定給ViewModel的屬性,這樣一來Knockout.js之後就可以替我們處理了。
接下則是ko.applyBindings這個方法,它其實就是註冊一個ViewModel,讓它可以套用資料繫連的工作。
我們看一下HTML中兩個data-bind的tag,對應的就是ViewModel的值和方法。這裡很特別的是,我們沒有看到任何的事件註冊,像是jQuery中的click綁定,事實上透過data-bind="click:increase" 這個值的指定,已經做完事件監聽了。
至此,Knockout.js已經完工了。
jQuery版本的DEMO
http://jsfiddle.net/brecht/fYvvU/5/
Knockout.js的DEMO
http://jsfiddle.net/brecht/VgZ9k/
[Knockout.js的威力在...]
表面上看起來,似乎Knockout.js寫的code沒有精簡多少,而且還得建立一個ViewModel,看起來沒有比jQuery直覺容易。
的確,表面上看起來是如此,不過就讓我們來試試Knockout.js的威力所在。
我們來替HTML加上的個<h2>的tag,然後一樣讓它顯示報名的數量。
首先先來看jQuery的HTML:
<div id="register">
<h1>報名系統</h1>
<div>目前有<strong>0</strong>人報名</div>
<button>我要報名</button>
</div>
<h2><strong>0</strong>人報名</h2>
最底下的那行h2,用來顯示和原來報名人數一樣的數字。
那麼jQuery必須針對新加入的h2做一點處理。
var counter = $('#register div strong');
var counterH2 = $('h2 strong');
$('#register button').click(function(){
var counterValue = counter.text();
counterValue = ++counterValue;
counter.text(counterValue);
counterH2.text(counterValue);
});
就如同counter的DOM一樣,我們先抓住H2的DOM,存在counterH2中,然後在點擊事件時,一樣把新的值塞給它(DEMO看這裡:http://jsfiddle.net/brecht/fYvvU/4/)。
那麼Knockout.js又是怎麼處理的呢?讓我們先看HTML。
<div id="register">
<h1>報名系統</h1>
<div>目前有<strong data-bind="text:counter">0</strong>人報名</div>
<button data-bind="click:increase">我要報名</button>
</div>
<h2><strong data-bind="text:counter">0</strong>人報名</h2>
我們一樣為h2/strong加上data-bind的屬性。
然後就收工了。
什麼??JavaScript改都不用改??
沒錯,一個字都不用改,直接跑起來的結果就和jQuery的版本一樣。
這就是Knockout.js的威力所在啊(DEMO看這裡:http://jsfiddle.net/brecht/VgZ9k/1/)。
在體驗了Knockout.js的威力之後,下一次,我們會再深入一下Knockout.js的細節。如果你已經等不及的話,也可以到官網去看看,裡面的教學和文件,也可以讓你很快就上手。
[相關資源]
Knockout.js官網:http://knockoutjs.com/
Knockout.js下載:http://github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.js
新的framework出現得好多,目不睱給,
看了這篇具體實例的介紹,
勝讀三天的相關介紹。
也想知道,又有backbone.js或其他的framework,
好像各有不同的 M或V或C的 架構組合,
那麼多種的framework,
怎麼判斷何種適合解決怎樣的問題?
還是任何frmework都可解決任何問題?
這個問題好像也是:
有那麼多種的nosql,
哪種nosql適用在何種的問題 似的。
我也有類似的感覺啊,想說那麼多東西,看來看去也不太有感覺,就乾脆用寫文章的方式來學習。
現在是 MV* 盛行 的時代啊~
12种JavaScript MVC框架之比较:http://news.cnblogs.com/n/144303/
裡面比較了
<pre class="c" name="code">Backbone.js
SproutCore
Sammy.js
Spine.js
Cappuccino
Knockout.js
Javascript MVC
GWT(Google Web Toolkit)
Google Closure
Ember.js
Angular.js
Batman.js
而最後作者覺得Ember.js勝出。