在 Angular 4 中使用 trackBy 对 *ngFor 数组进行排序

Posted

技术标签:

【中文标题】在 Angular 4 中使用 trackBy 对 *ngFor 数组进行排序【英文标题】:sorting an *ngFor array with trackBy in Angular 4 【发布时间】:2018-07-03 05:38:25 【问题描述】:

我在排序和具有 trackBy 函数的数组时遇到问题。用例如下:

我有一个项目数组。所有这些项目都有一个 z-index 属性。我还有一个图层管理器​​,可以编辑每个项目的 z-index。当我想保存我的项目时,我想根据每个项目的 z-index 属性对我的数组进行排序。我的 ngFor 上还有一个 trackBy 来限制 *ngFor 上的更改检测量。

在我的 *ngFor 上使用 trackBy 函数,当我对数组进行排序时,项目会切换位置(这很糟糕)。如果我删除 trackBy 函数,这不会发生,并且项目根据 z-index 排序。

*ngFor:

<div class="item" *ngFor="let item of items; let i = index;trackBy:getUniqueIdentifier">

trackBy函数:

getUniqueIdentifier(index, item) 
    return this.items.length + ', ' + this.languages._previewLanguage;

如您所见,当项目的长度发生变化或我切换语言设置时,*ngFor 也会发生变化。我试过添加+ ', ' + item.zIndex,但这不起作用。

排序功能:

sortItemsArrayByZIndex() 
    this.items.sort((i1, i2) => 
        return (i1.zIndex - i2.zIndex);
    );

所以 trackBy 和这个 sort 函数似乎出于某种原因发生了冲突。现在的结果是,当我使用排序函数时,项目数组会根据 z-index 进行排序,但项目也会切换位置,这意味着它们的维度属性由于某种原因被切换。

我想要的是项目数组根据 z-index 排序,但项目保持它们的尺寸。

我需要如何更改我的 trackBy 函数或我的 sort 函数以获得我想要的结果?

【问题讨论】:

你为什么要在那里使用 trackBy 函数?您正在迭代非原始值,并且您正在返回一个不能唯一的值。你制作这首歌的目的是什么? 据我了解,trackBy 可用于确定 ngFor 何时需要进行更改检测,即重建。这段代码在一个相当大的项目中,出于性能原因,我不希望 ngFor 在每次发生变化时都进行变化检测,所以这就是我有 trackBy 的原因。但也许我对 trackBy 的理解是错误的? 如果语言发生变化,每个项目都会被关注,但如果任何其他字段(或其索引)发生变化,则不会关注任何项目。这就是您的排序可能不起作用的原因:由于项目索引正在更改并且您没有跟踪它,因此没有发生更改检测。这是一个假设,但您可能应该对其进行测试:) 只需将索引添加到轨道的返回语句中,这应该可以解决问题! 很高兴我能帮上忙! 【参考方案1】:

如果您不介意,我会添加我自己的答案来解释为什么您的代码不起作用,因为您只提供了一个工作代码而没有任何解释。

trackBy 函数

trackBy 函数旨在提高性能,并避免不必要的更改检测。您可以像以前一样提供自定义函数,它会创建一个值,用于检查是否需要触发更改检测。

问题

你的 trackBy 函数是这样的:

getUniqueIdentifier(index, item) 
  return this.items.length + ', ' + this.languages._previewLanguage;

这将返回此类型的值:

90, en-US

90 不会改变除非您从数组中推送/撤回项目,而en-US 可以应用于数组的多个项目。这意味着如果您更改索引或其他字段,则不会发生更改检测。

解决办法

由于您要对数组进行排序,您必须至少将 索引 添加到自定义函数的返回值中。这意味着如果项目的索引发生变化(并且由于您对数组进行排序,它会发生变化),就会发生变化检测。

最小的代码是:

getUniqueIdentifier(index, item) 
  return index + ', ' + this.languages._previewLanguage + ', ' + this.items.length;

【讨论】:

嗯,谢谢,但更多的是解释问题!来 SOF 的人通常会看答案,而不是 cmets ...【参考方案2】:

正如用户@trichetriche 所说,我需要将索引以及 zIndex 属性添加到 trackBy 以让 TrackBy 按预期工作。

trackBy 函数如下所示:

getUniqueIdentifier(index, item) 
    return index + ', ' + item.zIndex + ', ' + this.languages._previewLanguage + ', ' + this.items.length;

【讨论】:

以上是关于在 Angular 4 中使用 trackBy 对 *ngFor 数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

Angular 9 Reactive Forms:使用 trackBy 时复选框未更新

typescript Angular - Ng For TrackBy for Performance

如何使用 `trackBy` 和 `ngFor`

trackBy 与异步管道

Angular 4 对 asp.net 核心 API 的请求(在标头中使用授权)不起作用

Angular实现虚拟滚动多选下拉框笔记