KnockoutJS 3.X API 第四章 數據綁定(2) 控制流foreach綁定


foreach綁定

foreach綁定主要用於循環展示監控數組屬性中的每一個元素,一般用於table標簽中

假設你有一個監控屬性數組,每當您添加,刪除或重新排序數組項時,綁定將有效地更新UI的DOM-插入或去除相關項目或重新排序現有的DOM元素,不影響任何其他的DOM元素。

當然,也可以配合其他控制流一起適用,例如ifwith

示例1:遍歷監控屬性數組

本例適用foreach綁定,在一個table標簽中循環顯示監控屬性數組的內容

<table>
    <thead>
        <tr><th>First name</th><th>Last name</th></tr>
    </thead>
    <tbody data-bind="foreach: people">
        <tr>
            <td data-bind="text: firstName"></td>
            <td data-bind="text: lastName"></td>
        </tr>
    </tbody>
</table>
 
<script type="text/javascript">
    ko.applyBindings({
        people: [
            { firstName: 'Bert', lastName: 'Bertington' },
            { firstName: 'Charles', lastName: 'Charlesforth' },
            { firstName: 'Denise', lastName: 'Dentiste' }
        ]
    });
</script>

示例2:添加或刪除項目

People

UI源碼:

<h4>People</h4>
<ul data-bind="foreach: people">
    <li>
        Name at position <span data-bind="text: $index"> </span>:
        <span data-bind="text: name"> </span>
        <a href="#" data-bind="click: $parent.removePerson">Remove</a>
    </li>
</ul>
<button data-bind="click: addPerson">Add</button>

視圖模型源碼:

function AppViewModel() {
    var self = this;
 
    self.people = ko.observableArray([
        { name: 'Bert' },
        { name: 'Charles' },
        { name: 'Denise' }
    ]);
 
    self.addPerson = function() {
        self.people.push({ name: "New at " + new Date() });
    };
 
    self.removePerson = function() {
        self.people.remove(this);
    }
}
 
ko.applyBindings(new AppViewModel());

 

備注1:使用$data

如前兩個示例中,foreach后面所跟的是要循環的監控屬性數組名稱,而foreach內部所跟隨的是監控屬性數組的項目,例如firstName和lastName。

當你想引用監控屬性數組本身的時候,就可以使用這個特殊的上下文$data,他所指的就是監控屬性數組本身。

例如,你的監控屬性數組中的項目沒有明確的項目名稱:

<ul data-bind="foreach: months">
    <li>
        The current item is: <b data-bind="text: $data"></b>
    </li>
</ul>
 
<script type="text/javascript">
    ko.applyBindings({
        months: [ 'Jan', 'Feb', 'Mar', 'etc' ]
    });
</script>

如何你願意的話,也可以使用$data來引用監控數組屬性中的項目,例如:

<td data-bind="text: $data.firstName"></td>

其實這是多此一舉的。因為firstName的默認前綴就是$data,所以一般可以省略不寫。

備注2:使用$index、$parent和其他的上下文標記

你可能會發現,在示例2中使用了$index來代替了監控屬性數組的索引值(從0開始),當然$index是一個監控屬性,他會根據數據的變化而自動變化,就像示例2中展示的一樣。

而$parent所代表的是在foreach綁定循環外的某個綁定屬性,例如:

<h1 data-bind="text: blogPostTitle"></h1>
<ul data-bind="foreach: likes">
    <li>
        <b data-bind="text: name"></b> likes the blog post <b data-bind="text: $parent.blogPostTitle"></b>
    </li>
</ul>

 

備注3:使用“as”給foreach綁定項目起個別名

在備注1中,使用$data.varibale的方式訪問的監控屬性數組的項目,但在有些時候你可以需要給這些項目起個別名,那就是可以使用as,例如:

<ul data-bind="foreach: { data: people, as: 'person' }"></ul>

現在,只要在foreach循環中,使用person,就可以訪問數組中的元素了。

也有些嵌套使用的例子,這中會更加復雜一些,例如:

<ul data-bind="foreach: { data: categories, as: 'category' }">
    <li>
        <ul data-bind="foreach: { data: items, as: 'item' }">
            <li>
                <span data-bind="text: category.name"></span>:
                <span data-bind="text: item"></span>
            </li>
        </ul>
    </li>
</ul>
 
<script>
    var viewModel = {
        categories: ko.observableArray([
            { name: 'Fruit', items: [ 'Apple', 'Orange', 'Banana' ] },
            { name: 'Vegetables', items: [ 'Celery', 'Corn', 'Spinach' ] }
        ])
    };
    ko.applyBindings(viewModel);
</script>

備注4:不使用foreach容器並生產內容

在某些情況下,可能需要復制容器標簽的內容,例如生成如下DOM:

<ul>
    <li class="header">Header item</li>
    <!-- The following are generated dynamically from an array -->
    <li>Item A</li>
    <li>Item B</li>
    <li>Item C</li>
</ul>

像這種情況,我們就無法在ul標簽中使用foreach綁定,解決這個問題的方法就是使用無容器的foreach綁定:

<ul>
    <li class="header">Header item</li>
    <!-- ko foreach: myItems -->
        <li>Item <span data-bind="text: $data"></span></li>
    <!-- /ko -->
</ul>
 
<script type="text/javascript">
    ko.applyBindings({
        myItems: [ 'A', 'B', 'C' ]
    });
</script>

這里使用虛擬元素容器,<!-- ko --><!-- /ko -->。就想之前章節提到的虛擬綁定一樣。

備注5:檢測並處理數組變化

當您修改模型數組的內容(通過添加,移動或刪除其項),在foreach綁定使用一個有效的差分算法計算方法當出發生了什么變化的時候。

  • 當您添加數組項,foreach會使您的模板的新副本,並將其插入到現有的DOM
  • 當你刪除數組項,foreach將直接刪除相應的DOM元素
  • 當你重新排序數組項(保持相同的對象實例),foreach通常只要將相應的DOM元素融入自己的新位置

備注6:銷毀項目

有時你可能想為數據項目做刪除標記,但實際上並不真正刪除該項目。這中方式被稱為非破壞性的刪除

默認情況下,foreach綁定將跳過(即隱藏)標記為刪除任何數組項。如果你想顯示這些項目,使用includeDestroyed選項。例如,

<div data-bind='foreach: { data: myArray, includeDestroyed: true }'>
    ...
</div>

備注7:使用動畫過渡,提高用戶體驗

如果您需要在生成的DOM元素運行一些定制邏輯,你可以使用afterRender/ afterAdd/beforeRemove/ beforeMove/ afterMove這些回調函數。

下面是一個使用afterAdd一個簡單的例子,應用經典的“黃色淡出”的效果,以新增項目。它需要的jQuery插件的顏色,使背景色彩的動畫。

 

源碼如下:

<ul data-bind="foreach: { data: myItems, afterAdd: yellowFadeIn }">
    <li data-bind="text: $data"></li>
</ul>
 
<button data-bind="click: addItem">Add</button>
 
<script type="text/javascript">
    ko.applyBindings({
        myItems: ko.observableArray([ 'A', 'B', 'C' ]),
        yellowFadeIn: function(element, index, data) {
            $(element).filter("li")
                      .animate({ backgroundColor: 'yellow' }, 200)
                      .animate({ backgroundColor: 'white' }, 800);
        },
        addItem: function() { this.myItems.push('New item'); }
    });
</script>

一些具體的細節

    • afterRender-當foreach第一次初始化執行的回調函數。KO提供下列參數回調:

      1. 插入的DOM元素的數組
      2. 數據項
    • afterAdd-當foreach添加新項目后的回調函數。KO提供下列參數回調:

      1. DOM節點
      2. 添加的數組元素的索引
      3. 添加的數組元素
    • beforeRemove-當一個數組項已被刪除的回調函數。這里最明顯的用jQuery的$(domNode).fadeOut()動畫去除相應的DOM節點。KO提供下列參數回調:

      1. 刪除一個DOM節點
      2. 被刪除的數組元素的索引
      3. 刪除的數組元素
    • beforeMove-當一個數組項在數組中已經改變了位置的回調函數,但之前相應的DOM節點已被移動。需要注意的是beforeMove適用於所有的數組元素的指標發生了變化,因此,如果你在一個數組的開頭插入一個新的項目,然后回調(如果指定)將觸發所有其他元素,因為它們的索引位置增加了一個。您可以使用beforeMove存儲在受影響元素的原始屏幕坐標,這樣你可以在afterMove回調動畫動作。KO提供下列參數回調:

      1. 可能是移動的DOM節點
      2. 移動的數組元素的索引
      3. 移動的數組元素
    • afterMove-數組項在數組中已經改變位置的回調函數,KO提供下列參數回調:

      1. 可能已經移動的DOM節點
      2. 移動的數組元素的索引
      3. 移動的數組元素

結語

本來想把整個控制流綁定在一節里寫完的,但是發現一個foreach就有很多內容,所以控制流綁定將分成多節來寫,盡請讀者見諒。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM