KO範例6 - 陣列元素的新增/移除事件
範例4已展示KO完全掌握observableArray()陣列元素增減,即時反應在UI的能力。但如果我們希望在陣列增加或移除元素時加上自訂邏輯,要怎麼做?
foreach提供了afterAdd及beforeRemove兩個額外的事件繫結設定,允許在陣列新增、移除元素時執行特定邏輯。在此繼續沿用先前的使用者清單呈現範例,加上兩個效果:
- 新增資料時,將最新加入的資料標為暗紅字
- 刪除資料時,加上資料淡出後消失的特效
而在ViewModel裡我們加上兩個函數:
//第一次foreach產生時不會觸發,只有事後加入才會
self.afterAddEvent = function (elems, idx, data) {
//Template中的Text Node與Element Node會分別觸發多次
//在本例中會因Text, Element, Text共觸發三次
//透過nodeType過濾,只處理Element Node
if (elems.nodeType == 1) //Element Node
{
$(".new").removeClass("new");
$(elems).addClass("new");
}
};
//注意: 掛載beforeRemove事件後,要自已負責移除被刪除元素
self.b4RemoveEvent = function (elems, idx, data) {
if (elems.nodeType == 1) {
$(elems)
.css("background-color", "red")
.animate({ opacity: 0.2 }, 500, function () {
$(this).remove();
})
}
};
afterAdd及beforeRemove函數會固定收到三個參數,elems、index及data,其中elems為範本容器中的各元素,在本範例中,就是以下黃底紅字部分:
<tbody data-bind="foreach: { data: users, afterAdd: afterAddEvent, beforeRemove: b4RemoveEvent }">
<tr>
<td><span data-bind="text: id"></span></td>
<td><span data-bind="text: name"></span></td>
<td><span data-bind="text: score" style='text-align: right'></span></td>
<td><a href='#' data-bind="click: $root.removeUser">移除</a></td>
</tr>
</tbody>
但此處有個小訣竅,實際運作時afterAdd/beforeRemove會收到不同的elems被呼叫三次,原因是除了<tr>之外,<tbody>到<tr>之間的空白、</tr>到</tbody>間的空白也各算一個Element,其nodeType為3,代表TEXT_NODE。因此三次傳入的elems分別為TEXT_NODE、ELEMENT_NODE、TEXT_NODE,而第二次傳入的ELEMENT_NODE是<tr>…</tr>間的內容,才是我們需要處理的對象,故加入if (elems.nodeType == 1)的判斷式。
最新加入資料的特別標示,在此透過addClass("new")來達成;至於移除資料的特效,則先為<tr>加上不透明度(opacity)由100%降到20%的動畫,然後在動畫完成後,將其自<tbody>中移除。要注意,一旦掛載了beforeRemove,KO就不再自動幫你移除該筆資料在網頁對應的元素,必須自行處理,但這也提供開發人員絕對的控制權,可自由安排HTML元素要怎麼從網頁上退場。


線上展示
[KO系列]
http://www.darkthread.net/kolab/labs/default.aspx?m=post