AngularJS 中的 "track by" 是什么,它是如何工作的?
What is "track by" in AngularJS and how does it work?
我不太明白 track by
的工作原理和作用。
我的主要目标是将它与 ng-repeat
一起使用以增加一些精度。
当您添加 track by
时,您基本上告诉 angular 为给定集合中的每个数据对象生成一个 DOM 元素。
如果您的数据源具有重复标识符,您可以track by $index
。
如果您确实需要重复重复的项目,您可以使用 track by expression 将默认跟踪行为替换为您自己的行为。
示例:
[{id:1,name:'one'}, {id:1,name:'one too'}, {id:2,name:'two'}]
尝试使用 ng-repeat
中的重复值,你会得到如下错误:
Error: 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>
以下资源可能对您有所帮助:
仅当您需要违背 ng-repeat
的默认行为(删除重复项目)时才应使用 track by
。
您可以使用范围 属性 $index
或指定自定义函数来跟踪项目。
例如:
<div ng-repeat="x in [42, 42, 43, 43] track by $index">
{{x}}
</div>
显示数组的所有值(42显示两次)。
使用 track by
跟踪字符串和重复值
通常 ng-repeat
按项目本身跟踪每个项目。对于给定的数组 objs = [ 'one', 'one', 2, 'five', 'string', 'foo']
,ng-repeat
尝试跟踪 ng-repeat="obj in objs"
中每个 obj
的变化。问题是我们有重复的值, angular 会抛出错误。解决该问题的一种方法是让 angular 通过其他方式跟踪对象。对于字符串,track by $index
是一个很好的解决方案,因为您确实没有其他方法来跟踪字符串。
track by
& 触发摘要 & 输入焦点
你暗示你对 angular 有点陌生。当 angular 对每个观看的 属性 执行详尽检查以反映对相应视图的任何更改时,就会发生摘要循环;通常在摘要周期中,您的代码会修改其他监视的属性,因此需要再次执行该过程,直到 angular 检测不到更多更改。
例如:您单击一个按钮通过 ng-click
更新模型,然后您执行某些操作(我的意思是,您在回调中编写的内容在用户点击时执行),然后 angular 触发摘要循环以刷新视图。我解释得不是很清楚,所以如果这不能说明问题,你应该进一步调查。
所以回到track by
。让我们举个例子:
- 为return对象数组调用服务
- 更新数组中的对象并保存对象
- 保存服务后,根据 API return 的内容,您可以:
- 替换整个对象或
- 更新现有对象的值
- 反映
ng-repeat
UI 的变化
您如何跟踪此对象将决定 UI 如何反映更改。
这是我经历过的最烦人的用户体验之一。假设您有 table 个对象,每个单元格都有一个输入,您可以在其中内联编辑这些对象的属性。我想更改值,然后 on-blur
,保存该对象,同时移动到下一个单元格进行编辑,而您可能正在等待响应。所以这是一个自动保存类型的东西。根据您设置 track by
语句的方式,当响应被写回您的对象数组时,您可能会失去当前焦点(例如您当前正在编辑的字段)。
比方说,我们有以下列表:
<ul>
<li ng-repeat="item in items">
{{ item }}
</li>
</ul>
其中,项目具有以下结构:
{ 'id'=>id, 'name'=>name, 'description'=>description }
在我们希望更新之前,此列表没有任何问题。为了我们自己的方便,我们将项目列表替换为另一个更新的项目列表,如下所示:
items = newItems;
但是,在这个新列表中,很少有项目发生变化。大多数项目保持不变。不幸的是 Angular 不知道如何识别我们的项目并将它们映射到相应的 <li>
元素,因此它只是删除所有元素并重新创建它们。在某些情况下,这会非常耗费性能,这就是 track by
派上用场的地方。
通过向元素添加 track by
子句
<li ng-repeat="item in items track by item.id">
我们通知 Angular,我们项目的唯一标识符是 item.id
。现在 Angular 知道不重新创建所有项目,而只重新创建具有新 ID 的项目,并且只更新其余项目。在大多数情况下,性能改进是显着的。另外,就个人而言,我喜欢我可以在浏览器的开发人员工具上更轻松地监控我的项目,因为它们不会在我每次更新时消失。
我不太明白 track by
的工作原理和作用。
我的主要目标是将它与 ng-repeat
一起使用以增加一些精度。
当您添加 track by
时,您基本上告诉 angular 为给定集合中的每个数据对象生成一个 DOM 元素。
如果您的数据源具有重复标识符,您可以track by $index
。
如果您确实需要重复重复的项目,您可以使用 track by expression 将默认跟踪行为替换为您自己的行为。
示例:
[{id:1,name:'one'}, {id:1,name:'one too'}, {id:2,name:'two'}]
尝试使用 ng-repeat
中的重复值,你会得到如下错误:
Error: 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>
以下资源可能对您有所帮助:
仅当您需要违背 ng-repeat
的默认行为(删除重复项目)时才应使用 track by
。
您可以使用范围 属性 $index
或指定自定义函数来跟踪项目。
例如:
<div ng-repeat="x in [42, 42, 43, 43] track by $index">
{{x}}
</div>
显示数组的所有值(42显示两次)。
使用 track by
跟踪字符串和重复值
通常 ng-repeat
按项目本身跟踪每个项目。对于给定的数组 objs = [ 'one', 'one', 2, 'five', 'string', 'foo']
,ng-repeat
尝试跟踪 ng-repeat="obj in objs"
中每个 obj
的变化。问题是我们有重复的值, angular 会抛出错误。解决该问题的一种方法是让 angular 通过其他方式跟踪对象。对于字符串,track by $index
是一个很好的解决方案,因为您确实没有其他方法来跟踪字符串。
track by
& 触发摘要 & 输入焦点
你暗示你对 angular 有点陌生。当 angular 对每个观看的 属性 执行详尽检查以反映对相应视图的任何更改时,就会发生摘要循环;通常在摘要周期中,您的代码会修改其他监视的属性,因此需要再次执行该过程,直到 angular 检测不到更多更改。
例如:您单击一个按钮通过 ng-click
更新模型,然后您执行某些操作(我的意思是,您在回调中编写的内容在用户点击时执行),然后 angular 触发摘要循环以刷新视图。我解释得不是很清楚,所以如果这不能说明问题,你应该进一步调查。
所以回到track by
。让我们举个例子:
- 为return对象数组调用服务
- 更新数组中的对象并保存对象
- 保存服务后,根据 API return 的内容,您可以:
- 替换整个对象或
- 更新现有对象的值
- 反映
ng-repeat
UI 的变化
您如何跟踪此对象将决定 UI 如何反映更改。
这是我经历过的最烦人的用户体验之一。假设您有 table 个对象,每个单元格都有一个输入,您可以在其中内联编辑这些对象的属性。我想更改值,然后 on-blur
,保存该对象,同时移动到下一个单元格进行编辑,而您可能正在等待响应。所以这是一个自动保存类型的东西。根据您设置 track by
语句的方式,当响应被写回您的对象数组时,您可能会失去当前焦点(例如您当前正在编辑的字段)。
比方说,我们有以下列表:
<ul>
<li ng-repeat="item in items">
{{ item }}
</li>
</ul>
其中,项目具有以下结构:
{ 'id'=>id, 'name'=>name, 'description'=>description }
在我们希望更新之前,此列表没有任何问题。为了我们自己的方便,我们将项目列表替换为另一个更新的项目列表,如下所示:
items = newItems;
但是,在这个新列表中,很少有项目发生变化。大多数项目保持不变。不幸的是 Angular 不知道如何识别我们的项目并将它们映射到相应的 <li>
元素,因此它只是删除所有元素并重新创建它们。在某些情况下,这会非常耗费性能,这就是 track by
派上用场的地方。
通过向元素添加 track by
子句
<li ng-repeat="item in items track by item.id">
我们通知 Angular,我们项目的唯一标识符是 item.id
。现在 Angular 知道不重新创建所有项目,而只重新创建具有新 ID 的项目,并且只更新其余项目。在大多数情况下,性能改进是显着的。另外,就个人而言,我喜欢我可以在浏览器的开发人员工具上更轻松地监控我的项目,因为它们不会在我每次更新时消失。