[TOC]

入门

监控属性

使用内置绑定

控制文本和外观

绑定逻辑控制

处理表单属性

解析模板

高级应用

插件

更多信息

"foreach" 绑定

目的

foreach 绑定将array中项目绑定到每个重复的节点中,并且将节点的副本绑定到对应的数组项中。在呈现列表或表格的这尤其有用。

The foreach binding duplicates a section of markup for each entry in an array, and binds each copy of that markup to the corresponding array item. This is especially useful for rendering lists or tables.

假设你的数组是一个 observable array,每当你添加或删除数组条目时,绑定可以自动更新对应的UI元素 - 插入或删除更多的副本,而不会影响到其他的DOM元素。

Assuming your array is an observable array, whenever you later add or remove array entries, the binding will efficiently update the UI to match - inserting or removing more copies of the markup, without affecting any other DOM elements.

当然你也是随意嵌套任何流程控制绑定 foreachifwith

Of course, you can arbitrarily nest any number of foreach bindings along with other control-flow bindings such as if and with.

例子1: 遍历数组

这个例子使用 foreach 遍历绑定一个只读表格。

<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:添加和删除项目

下面的示例显示,如果你使用observableArray,那么用户界面与数组的更改保持同步。

The following example show that, if your array is observable, then the UI will be kept in sync with changes to that array.

People

  • Name: Remove

源码: View

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

源码: View model

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());

参数

  • 主参数

传入你要遍历的数组。的结合将输出一个标记为每个条目。

Pass the array that you wish to iterate over. The binding will output a section of markup for each entry.

或者,传入 JavaScript 文本对象和你想遍历的数组属性名。对象文本也可能有其他属性,例如 afterAddincludeDestroyed — 这些额外的选项的详细信息和示例,请参阅以下使用。

Alternatively, pass a JavaScript object literal with a property called data which is the array you wish to iterate over. The object literal may also have other properties, such as afterAdd or includeDestroyed — see below for details of these extra options and examples of their use.

如果您提供的是 observable, foreach 绑定会将数组的变化更新到DOM中响应部分。

If the array you supply is observable, the foreach binding will respond to any future changes in the array’s contents by adding or removing corresponding sections of markup in the DOM.

  • 附加参数

注1: 在遍历项中使用$data

如上述例子所示,foreach块的绑定可以参考数组项的属性。例如, 例1参考 firstNamelastName 每个数组中项目。

As shown in the above examples, bindings within the foreach block can refer to properties on the array entries. For example, Example 1 referenced the firstName and lastName properties on each array entry.

但是,如果你要引用数组项本身(它不只是一个属性)?这种情况下,你可以使用伪变量 $data。在 foreach 块中,它相当于当前遍历到的项目。例如,

But what if you want to refer to the array entry itself (not just one of its properties)? In that case, you can use the pseudovariable $data. Within a foreach block, it means “the current item”. For example,

<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 作为每个遍历项目的前缀。例如, 你可以将 例1 改写成如下:

If you wanted, you could use $data as a prefix when referencing properties on each entry. For example, you could rewrite part of Example 1 as follows:

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

… 但是你没必要这么做, 因为默认情况下 firstName 包含在 $data 内。

… but you don’t have to, because firstName will be evaluated within the context of $data by default anyway.

注2: 结合绑定上下文使用 $parent, $parents, 和 $root

当你嵌套流程控制绑定时, 通常需要访问当前项的父级。你可以使用下面的伪变量:

When you’re nesting control-flow bindings, it’s often desirable to reach back up the hierarchy and access data or functions from parent contexts. You can use the following pseudovariables:

  • $parent — 是当前 foreach 块项以外

$parent — is the data item outside the current foreach block

  • $parents — 是一个数组,它表示数据的所有外部流控制范围中的项目。

$parents — is an array representing data items from all outer control-flow scopes.

  • $parents[0] 是父控制流范围项目 (它等价于 $parent)
  • $parents[0] is the item from the parent control-flow scope (i.e., it’s the same as $parent)
  • $parents[1] 是祖父控制流范围的项目
  • $parents[1] is the item from the grandparent control-flow scope
  • $parents[2] 是曾祖父控制流项范围
  • $parents[2] is the item from the great-grandparent control-flow scope
  • … 等等
    • 在流程中 $root 是外层的项目。通常这是你viewmodel中追顶端对象。等同于 $parents[$parents.length-1]

$root is the item from the outer-most control-flow scope. Typically this is your top-level viewmodel object. This is the same as $parents[$parents.length-1].

例如,请查看带有 $parent例2

For example, see the use of $parent in Example 2.

注3: 在容器元素上使用foreach

在某些情况下,你可能需要遍历复制某些元素标签,但是你没有可用于 foreach 绑定的容器元素。请查看下面例子:

In some cases, you might want to duplicate a section of markup, but you don’t have any container element on which to put a foreach binding. For example, you might want to generate the following:

<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>

在这个例子中, 你不能将 foreach 绑定放置在

    标签上 (因为你会的到重复的
      标签),也可以把容器设置在
        内部(因为只允许
      • 元素出现在
          内部)。

          In this example, there isn’t anywhere to put a normal foreach binding. You can’t put it on the

            (because the you’d be duplicating the header item), nor can you put a further container inside the
              (because only
            • elements are allowed inside
                s).

                为了解决这个问题,你可以使用无容器的控制流的语法,它是基于注释标签。例如,

                To handle this, you can use the containerless control flow syntax, which is based on comment tags. For example,

                <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>

                注释标签作为开始/结束的标记,定义一个“虚拟元素”将要遍历的项包含在里面。Knockout能够认识这个虚拟元素的语法和绑定。

                The and comments act as start/end markers, defining a “virtual element” that contains the markup inside. Knockout understands this virtual element syntax and binds as if you had a real container element.

                注4: 带有Destroyed标识的项目默认是隐藏的

                有的时候您用Destroyed标记了数组中将要删除条目,但是实际上还没有真正的移除那个条目。无损删除。更多使用详情,请查看 observableArray中使用destroy方法.

                Sometimes you may want to mark an array entry as deleted, but without actually losing record of its existence. This is known as a non-destructive delete. For details of how to do this, see the destroy function on observableArray.

                默认情况下,foreach 绑定会跳过(就是., 隐藏) 数组中重带有destroyed标记的元素。如果你想要显示destroyed的元素,请设置 includeDestroyed 选项为 true。例如,

                By default, the foreach binding will skip over (i.e., hide) any array entries that are marked as destroyed. If you want to show destroyed entries, use the includeDestroyed option. For example,

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

                Note 5: Post-processing or animating the generated DOM elements

                如果您需要运行进一步的自定义逻辑生成DOM元素,你可以使用以下任何方法回调:

                If you need to run some further custom logic on the generated DOM elements, you can use any of the following callbacks:

                • afterRender — 在每次调用 foreach 将被插入到文档中,当 foreach 首次初始化时和新的元素被添加到关联数组中的时候。 Knockout 将提供下列回调参数:

                afterRender — is invoked each time the foreach block is duplicated and inserted into the document, both when foreach first initializes, and when new entries are added to the associated array later. Knockout will supply the following parameters to your callback:

                • 把数组插入到DOM中
                • 正在绑定的数据项
                • An array of the inserted DOM elements
                • The data item against which they are being bound
                • afterAdd — 和afterRender很像,除非方法被直接调用,否则只有当新的项目被添加到您的数组中时调用此方法 (而不是 当 foreach 初始化遍历项目时)。afterAdd 常见的用途是调用其他方法,如JQuery中 $(domNode).fadeIn() 在添加项目时启用动画效果。 Knockout 将提供下列回调参数:

                afterAdd — is like afterRender, except it is invoked only when new entries are added to your array (and not when foreach first iterates over your array’s initial contents). A common use for afterAdd is to call a method such as jQuery’s $(domNode).fadeIn() so that you get animated transitions whenever items are added。 Knockout will supply the following parameters to your callback:

                • DOM节点将被添加到文档
                • 被添加数组元素的引索
                • 被添加数组的元素
                • A DOM node being added to the document
                • The index of the added array element
                • The added array element
                • beforeRemove — 此方法当数组项被删除时调用,但相应的DOM节点一辈删除。如果指定了 beforeRemove 回调,它将帮你自动移除相应的DOM节点。例如 jQuery’s方法 $(domNode).fadeOut() 删除DOM节点的同时添加动画效果 — 在这个例子中, Knockout 不知道DOM节点什么时候被删除 (谁知道你的动画要多久?),所以你是这样删除的。Knockout将提供下列回调参数:

                beforeRemove — is invoked when an array item has been removed, but before the corresponding DOM nodes have been removed. If you specify a beforeRemove callback, then it becomes your responsibility to remove the DOM nodes. The obvious use case here is calling something like jQuery’s $(domNode).fadeOut() to animate the removal of the corresponding DOM nodes — in this case, Knockout cannot know how soon it is allowed to physically remove the DOM nodes (who knows how long your animation will take?), so it is up to you to remove them. Knockout will supply the following parameters to your callback:

                • 被删除的DOM节点
                • 被删除的数组元素引索
                • 被删除的数组元素项
                • A DOM node that you should remove
                • The index of the removed array element
                • The removed array element

                这里有个简单的例子,使用 afterRender。试用JQuery $.css 使呈现的元素变为红色:

                Here’s a trivial example that uses afterRender. It simply uses jQuery’s $.css to make the rendered element turn red:

                <ul data-bind="foreach: { data: myItems, afterRender: handleAfterRender }">
                    <li data-bind="text: $data"></li>
                </ul>
                
                <script type="text/javascript">
                    ko.applyBindings({
                        myItems: ko.observableArray([ 'A', 'B', 'C' ]),
                        handleAfterRender: function(elements, data) {
                            $(elements).css({ color: 'red' });
                        }
                    });
                </script>

                请查看 afterAddbeforeRemove 的例子 animated transitions.

                For examples of afterAdd and beforeRemove see animated transitions.

                依赖性

                除KO核心类库外,无依赖。

                (c) knockoutjs.com