在第一篇有提到如果你的Web應用主要再處理一些CRUD,那很適合用knockout.js來實現MVVM架構,後續介紹了屬性、事件的控制,這篇就要來介紹在knoctout.js對於資料的顯示及處理。
foreach
foreach可以綁定一組Array資料,只要很簡潔的程式碼,就能輕鬆的完成多筆顯示的功能,
首先,我們定義一個使用者的class,包含他的序號、姓名
再來到ViewMode去繫結這個User的陣列資料,而給值的方式跟以往不一樣,observableArray()主要用來繫結陣列,如果你這個陣列資料有任何變動,如新增、刪除,他會自動同步到UI的顯示。
接著我們新增假資料,讓頁面載入就有三筆資料
HTML部分才是強大的地方!只要用以下指定方式即可!
Table 呈現方式:
清單呈現方式:
接著我們加入新增和移除的功能,程式很單純,可往下看完整程式碼應該很好懂,要特別注意的是,如果我們要針對某列做處理,可以用$parent這個參數來取得父元素,如下圖,在某列點選移除,取得該列的TR,則可針對這筆TR做處理:
除了$parent外,還有以下方式:
$parents – 抓取所有外部的元素 ex :
$parents[0] - 此元素的父類別,以此例來說即為 TR (等同於$parent)
$parents[1] - 此元素的父類別的父類別(好饒舌),以此例來說即為 tbody …以此類推
$root - 抓取最外層的元素,以此例來說即為 body ,(等同於$parents[$parents.length-1])
以下附上新增&刪除的完整程式碼:
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script src="Scripts/jquery-1.7.2.min.js"></script>
<script src="Scripts/knockout-2.1.0.debug.js"></script>
<button data-bind="click: AddUser">Add</button>
<button id="btn_json">Json</button>
<fieldset>
<legend>Table 呈現</legend>
<table>
<thead>
<tr>
<th>Number</th>
<th>First name</th>
<th>Last name</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: users">
<tr>
<td data-bind="text: Index"></td>
<td data-bind="text: firstName"></td>
<td data-bind="text: lastName"></td>
<td>
<button data-bind="click: $parent.RemoveUser">移除</button>
</td>
</tr>
</tbody>
</table>
</fieldset>
<fieldset>
<legend>清單呈現</legend>
<ul data-bind="foreach: users">
<li>
<span data-bind="text: Index">:</span>
<span data-bind="text: firstName"></span>
<span data-bind="text: lastName"></span>
<button data-bind="click: $parent.RemoveUser">移除</button>
</li>
</ul>
</fieldset>
<script type="text/javascript">
//定義使用者
var User = function (Index, firstName, lastName) {
var self = this;
self.Index = Index;
self.firstName = firstName;
self.lastName = lastName;
}
//ViewModel
var viewModel = function () {
var self = this;
self.users = ko.observableArray();
//新增使用者事件
self.AddUser = function () {
var index = self.users().length + 1;
model.users.push(new User(index, "Kyle", "Shen" + index));
}
//移除使用者事件
self.RemoveUser = function () {
self.users.remove(this);
}
}
//手動新增3筆假資料
var model = new viewModel();
for (var i = 1; i <= 3; i++) {
model.users.push(new User(i, "Kyle", "Shen" + i));
}
ko.applyBindings(model);
</script>
執行結果圖
fillano大 您好,
因在KO中,某些函數或function,this可能會代表其他涵義,為了避免混亂,故官方的Sample code可以看到都是按照此撰寫風格,針對這點,官方也有解釋:http://knockoutjs.com/documentation/computedObservables.html
您也可參考黑暗大的系列文(大推!!) http://blog.darkthread.net/post-2012-09-06-kolab1.aspx
謝謝您的回覆!
是在knockout處理data-bind時,會改變什麼嗎?我想:
<pre class="c" name="code">
var User = function (Index, firstName, lastName) {
var self = this;
self.Index = Index;
self.firstName = firstName;
self.lastName = lastName;
}
上面這一段code,this應該不會有問題才對。
但是:
<pre class="c" name="code">
self.AddUser = function () {
var index = self.users().length + 1;
model.users.push(new User(index, "Kyle", "Shen" + index));
}
//移除使用者事件
self.RemoveUser = function () {
self.users.remove(this);
}
是否會因為事件bind到DOM上面,所以改變了this參考的物件,造成問題,所以knockout建議在開始的時候把this指派給一個變數,然後利用closure使用到這個變數,這樣才不會出問題?另外在做compute的時候,也會因為改變了read/write函數的context,所以不能直接在裡面使用this?
利用var self=this;這樣的pattern來避開who is this的問題我沒有太多的問題。
另外,測試了一下,如果瀏覽器的Javascript支援ECMA-5標準,那可以這樣做:
<pre class="c" name="code">
var viewModel = function () {
var self = this;
this.users = ko.observableArray();
//新增使用者事件
this.AddUser = function () {
var index = this.users().length + 1;
model.users.push(new User(index, "Kyle", "Shen" + index));
}.bind(this);
//移除使用者事件
this.RemoveUser = function () {
self.users.remove(this);
};
}
這樣是不把this改成self的極限,但是在RemoveUser裡面不能這樣用,看起來這裡的this是需要參考到DOM物件,才有辦法把它從畫面上刪除。
這只是實驗就是了,實務上怎麼寫比較不會出錯,還是用他的best practice比較好。