【问题标题】:What is "track by" in AngularJS and how does it work?AngularJS 中的“track by”是什么,它是如何工作的?
【发布时间】:2020-07-16 16:35:48
【问题描述】:

我不太明白track by 的工作原理和作用。
我的主要目标是将它与ng-repeat 一起使用以增加一些精度。

【问题讨论】:

    标签: javascript angularjs ng-repeat angularjs-track-by


    【解决方案1】:

    使用track by 跟踪字符串和重复值

    通常ng-repeat 按项目本身跟踪每个项目。对于给定数组objs = [ 'one', 'one', 2, 'five', 'string', 'foo']ng-repeat 尝试跟踪ng-repeat="obj in objs" 中每个obj 的更改。问题是我们有重复的值,而 angular 会抛出一个错误。解决该问题的一种方法是通过其他方式对对象进行角度跟踪。对于字符串,track by $index 是一个很好的解决方案,因为您确实没有其他方法可以跟踪字符串。

    track by & 触发摘要 & 输入焦点

    你暗示你对 Angular 有点陌生。当 Angular 对每个观察到的属性进行详尽的检查以反映对应视图的任何变化时,就会出现一个摘要循环;通常在摘要周期中,您的代码会修改其他监视的属性,因此需要再次执行该过程,直到 angular 检测到不再有更改。

    例如:您单击一个按钮以通过ng-click 更新模型,然后执行某些操作(我的意思是,您在回调中编写的内容以在用户单击时执行),然后角触发摘要循环为了刷新视图。我解释得不是很清楚,所以如果这不能澄清事情,你应该进一步调查。

    所以回到track by。举个例子:

    1. 调用服务返回对象数组
    2. 更新数组中的对象并保存对象
    3. 保存服务后,根据 API 返回的内容,您可以:
      1. 替换整个对象或
      2. 更新现有对象的值
    4. 反映ng-repeat UI 中的变化

    您如何跟踪此对象将决定 UI 如何反映更改。

    我经历过的最烦人的用户体验之一就是这个。假设您有一个对象表,每个单元格都有一个输入,您希望在其中在线编辑这些对象的属性。我想更改值,然后on-blur,保存该对象,同时移动到下一个单元格进行编辑,而您可能正在等待响应。所以这是一个自动保存类型的东西。根据您设置 track by 语句的方式,当响应被写回您的对象数组时,您可能会失去当前焦点(例如,您当前正在编辑的字段)。

    【讨论】:

    • @Kyll 您在进行编辑时是正确的。在尝试写这篇文章时,我在后台还发生了 5 件事(比如尖叫的孩子)。感谢您修复它。
    【解决方案2】:

    当您添加track by 时,您基本上是告诉 Angular 为给定集合中的每个数据对象生成一个 DOM 元素。

    如果您的数据源有重复的标识符,您可以track by $index

    如果您确实需要重复重复项目,您可以使用逐个表达式的跟踪替换默认跟踪行为。

    例子:

    [{id:1,name:'one'}, {id:1,name:'one too'}, {id:2,name:'two'}]
    

    尝试使用ng-repeat中的重复值,会出现如下错误:

    错误:ngRepeat:dupes Duplicate Key in Repeater

    为避免此类问题,您应该使用track by $index。例如:

    <ul>
       <li ng-repeat="item in [1, 2, 3, 3] track by $index">
           {{ item }}
       </li>
    </ul>
    

    这是在嵌套的ng-repeat 中获取$index 的方法:

    <div ng-repeat="row in matrix">
        <div ng-repeat="column in row">
          <span>outer: {{$parent.$index}} inner: {{$index}}</span>
        </div>
    </div>
    

    以下是一些可能对您有所帮助的资源:

    【讨论】:

    • Codelord 是目前最好的 Angular 资源之一
    • “尝试在 ng-repeat 中使用重复值,你会得到一个错误” - 实际上,如果有人使用你的示例 [{id:1,name:'one'}, {id:1,name:'one too'}, {id:2,name:'two'}] 并使用 ng-repeat="obj in objects" 他赢了'不会出错,只有当数组中的两个对象是完全相同的对象(不仅是数据,在处理非原始值时也是相同的引用)时才会发生错误。
    【解决方案3】:

    仅当您需要违反ng-repeat 的默认行为(即删除重复项)时,才应使用track by
    您可以使用范围属性$index 或指定自定义函数来跟踪项目。

    例如:

    <div ng-repeat="x in [42, 42, 43, 43] track by $index">
      {{x}}
    </div>
    

    显示数组的所有值(42显示两次)。

    供参考:https://docs.angularjs.org/api/ng/directive/ngRepeat

    【讨论】:

      【解决方案4】:

      假设,我们有以下列表:

      <ul>
         <li ng-repeat="item in items">
             {{ item }}
         </li>
      </ul>
      

      其中,项目具有以下结构:

      { 'id'=>id, 'name'=>name, 'description'=>description }
      

      在我们希望对其进行更新之前,此列表中没有任何问题。为方便起见,我们将项目列表替换为另一个更新的项目列表,如下所示:

      items = newItems;
      

      但是,在这个新列表中,很少有项目发生变化。大多数项目保持不变。不幸的是,Angular 不知道如何识别我们的项目并将它们映射到各自的 &lt;li&gt; 元素,所以它只是删除所有元素并再次创建它们。在某些情况下,这非常耗费性能,这就是 track by 的用武之地。

      通过将track by 子句添加到元素

      <li ng-repeat="item in items track by item.id">
      

      我们通知 Angular,我们项目的唯一标识符是 item.id。现在 Angular 知道不重新创建所有项目,而只重新创建具有新 id 的项目,并且只更新其余的项目。在大多数情况下,性能改进是显着的。此外,就我个人而言,我喜欢在浏览器的开发者工具上更轻松地监控我的项目,因为它们不会在我每次更新它们时消失。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-13
        • 2018-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-19
        • 2012-11-06
        相关资源
        最近更新 更多