Angular 5中如何仅让数组新增项触发过渡动画?
解决Angular *ngFor仅让新增项触发动画的问题
当然可行!问题的根源在于Angular *ngFor 默认的跟踪机制,咱们来一步步调整就能实现你要的效果:
为什么现在所有项都会触发动画?
默认情况下,*ngFor 是通过对象引用来判断列表项是否为新元素的。当你在 ngOnInit 里替换整个数组时,哪怕是内容完全相同的项(比如示例里的 modulo 1 和 modulo 2),也都是新创建的对象,引用和之前不一样。Angular会把旧的DOM元素全部销毁,再重新创建所有项的DOM,这就导致所有元素都触发了 :enter 动画。
解决方案:使用 trackBy 函数
我们需要告诉Angular怎么识别列表项的唯一性,让它只对真正新增的项创建DOM并触发动画,已有项哪怕位置变化也不会重新渲染。
步骤1:在组件类中添加 trackBy 函数
在 ClientDetailComponent 里定义一个跟踪函数,返回每个模块的唯一标识(这里用 name,如果你的模块有唯一ID的话用ID会更稳妥):
export class ClientDetailComponent implements OnInit { activeModules = [{ name: 'modulo 1'}, { name: 'modulo 2'}]; // 添加trackBy函数 trackByModuleId(index: number, module: { name: string }): string { return module.name; // 用name作为唯一标识,确保每个模块name不重复 } ngOnInit(): void { Observable.timer(2000).subscribe(() => { this.activeModules = [{ name: 'modulo 1'}, { name: 'modulo 3'}, { name: 'modulo 2'}]; }); } }
步骤2:修改模板中的 *ngFor,绑定 trackBy
把跟踪函数加到 *ngFor 指令里:
<div class="row"> <div *ngFor="let m of activeModules; trackBy: trackByModuleId" [@enterAnimation]> {{ m.name }} </div> </div>
效果验证
这样修改后,当2秒后数组更新时:
- Angular会通过
trackByModuleId对比每个项的name,modulo 1和modulo 2已经存在,只会调整它们的DOM位置,不会重新创建,因此不会触发:enter动画; modulo 3是全新的项,没有匹配到已有的标识,Angular会创建新的DOM元素,自然触发你定义的透明度过渡动画。
注意事项
如果你的模块 name 可能存在重复,一定要换成真正唯一的标识(比如每个模块带的 id 属性),否则Angular会误判项的唯一性,导致动画或渲染异常。
内容的提问来源于stack exchange,提问作者Christian Benseler
相关产品推荐
相关产品推荐

