• 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就有很多内容,所以控制流绑定将分成多节来写,尽请读者见谅。

  • 相关阅读:
    正确使用c语言中的头文件
    用Python玩转大数据-入门阶段
    Python基础知识进阶(五---2)----程序基本结构、简单分支、异常处理、三大实例分析、基本循环结构、通用循环构造方法、死循环嵌套循环、布尔表达式
    Python基础知识进阶(五---1)----程序基本结构、简单分支、异常处理、三大实例分析、基本循环结构、通用循环构造方法、死循环嵌套循环、布尔表达式
    Python小程序练习(7个) 2017年9月28日---告诉自己多东西练习,而不是去空想
    python基础知识进阶(四) Python语言的math库和random库和实例
    python基础知识进阶(二) Python语言的数据类型
    python基础知识进阶之路(一)
    今天2017.5.23 开始一个web端网上商城项目的开发
    Lambda表达式(转载)
  • 原文地址:https://www.cnblogs.com/smallprogram/p/5930603.html
Copyright © 2020-2023  润新知