天天看點

Knockout.js随手記(7)

數組元素的新增/移除事件

前兩篇部落格已經很清楚的知道knockout.js通過observableArray()數組元素增減,可以實時的反映在UI上。當然我們想在數組增加或移除元素時加上自定義邏輯就好比一個觸發器的感覺,可以嗎?

foreach提供了afterAdd及beforeRemove兩個額外的事件,允許在數組新增、移除元素時執行特定邏輯。在此繼續沿用先前的使用者清單呈現範例,加上兩個效果:

  • 新增資料時,将最新加入的資料和表格進行着色修飾
  • 删除資料時,加上資料淡出特效

而在ViewModel裡我們加上兩個函數:

//添加對象後才觸發,第一次forach并不會觸發
            self.afterAddEvent = function (element, index, data) {
                //通過nodeType過濾,隻處理Element Node
                if (element.nodeType==1)  
                {
                    $(".new").removeClass("new");
                    $(element).addClass("new");
                }
            };
            //注意: beforeRemove事件後,要自已移除被刪除元素
            self.beforeRemoveEvent = function (element, index, data) {
                if (element.nodeType == 1) {
                    $(element)
                    .css("background-color", "#ff6a00")
                    .animate({ opacity: 0.2 },1000, function () {
                        $(this).remove();
                    })

                }
            };      

afterAdd及beforeRemove函數會固定收到三個參數,element、index及data,其中element為模闆容器中的各元素,即:

         <tr>
                    <td><span data-bind="text: id"></span></td>
                    <td><span data-bind="text: name"></span></td>
                    <td><span data-bind="text: score"></span></td>
                    <td><a href='#' data-bind="click: $root.removeUser">Remove</a></td>
                </tr>      

實際運作時afterAdd/beforeRemove會收到不同的element被呼叫三次,原因是除了<tr>之外,<tbody>到<tr>之間的空白、</tr>到</tbody>間的空白也各算一個Element,(FF和chrome是忽略這個空格的)其nodeType為3即TEXT_NODE,代表TEXT_NODE。是以三次傳入的element分别為TEXT_NODE、ELEMENT_NODE、TEXT_NODE,而第二次傳入的ELEMENT_NODE是<tr>...</tr>間的内容,才是我們需要處理的對象,故加入if (elems.nodeType == 1)的判斷。

要注意,一旦調用了了beforeRemove,konckout.js就不再自動幫你移除該筆資料在網頁對應的元素,必須自行處理,但這也提供開發人員絕對的控制權,可自由安排HTML元素要怎麼從網頁上退出。

完整代碼如下:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index2</title>
    <style>
        table { width: 385px }
        td,th { border: 1px solid #0094ff; text-align: center; }
        .new { color: #0094ff; background-color:#b6ff00}       
    </style>

    <script src="~/Scripts/jquery-2.0.3.js"></script>
    <script src="~/Scripts/knockout-2.3.0.js"></script>
    <script  type="text/javascript">
        //定義user資料對象
        function UserViewModel(id,name,score) {
            var self = this;
            self.id = id;
            self.name =ko.observable(name);
            self.score =ko.observable(score);
        }
        //定義ViewModel
        function ViewModel() {
            var self = this;
            self.users = ko.observableArray();//添加動态監視數組對象
            self.removeUser = function (user) {
                self.users.remove(user);
            }
            self.totalscore = ko.computed(function () {
                var total = 0;
                $.each(self.users(), function (i, u) {
                    total += u.score();
                })
                return total;
            });
            //添加對象後才觸發,第一次forach并不會觸發
            self.afterAddEvent = function (element, index, data) {
                //通過nodeType過濾,隻處理Element Node
                if (element.nodeType==1)  
                {
                    $(".new").removeClass("new");
                    $(element).addClass("new");
                }
            };
            //注意: beforeRemove事件後,要自已移除被刪除元素
            self.beforeRemoveEvent = function (element, index, data) {
                if (element.nodeType == 1) {
                    $(element)
                    .css("background-color", "#ff6a00")
                    .animate({ opacity: 0.2 },600, function () {
                        $(this).remove();
                    })

                }
            };
            };
        $(function () {
            var vm = new ViewModel();
            //預先添加一些資料
            vm.users.push(new UserViewModel("d1", "rohelm", 121));
            vm.users.push(new UserViewModel("d2", "halower", 125));
            $("#btnAddUser").click(function () { 
                vm.users.push(new UserViewModel(
                    $("#u_id").val(),
                    $("#u_name").val(),
                   parseInt($("#u_score").val())));
            });
            $("#btnUpdateScore").click(function () {
                vm.users()[vm.users().length-1].score(125).name("HelloWorld!");
            });
            ko.applyBindings(vm);
        });
    </script>
</head>
<body>
     <section style="margin:250px">
         <section>
         ID<input type="text" id="u_id" style="width:30px">
         Name<input type="text" id="u_name" style="width:30px">
         Score<input type="text" id="u_score" style="width:30px"><br/>
         <input  value="Add" id="btnAddUser" type="button" style="width:200px; background-color:#ff6a00;"/><br/>
           共 <span data-bind="text: users().length"></span> 條--------------合計 <span data-bind="text: totalscore"></span> 分
       </section>
       <section>
           <table>
            <thead>
                <tr><th>ID</th><th>Name</th><th>Score </th><th>Option</th></tr>
            </thead>
            <tbody  data-bind="foreach: { data: users, afterAdd: afterAddEvent, beforeRemove: beforeRemoveEvent}">
                <tr>
                    <td><span data-bind="text: id"></span></td>
                    <td><span data-bind="text: name"></span></td>
                    <td><span data-bind="text: score"></span></td>
                    <td><a href='#' data-bind="click: $root.removeUser">Remove</a></td>
                </tr>
            </tbody>
        </table>
            <input  value="Update測試" id="btnUpdateScore" type="button" style="width:200px; background-color:#ff6a00;"/><br/>
       </section>
     </section>
</body>
</html>      

運作效果如下:

Knockout.js随手記(7)

備注:

    本文版權歸大家共用,不歸本人所有,所有知識都來自于官網支援,書本,國内外論壇,大牛分享等等......後續将學習knockout.js的常用功能。

                                如果你喜歡本文的話,推薦共勉,謝謝!