如何在 Angular 中为 *ngFor 设置动画?
Posted
技术标签:
【中文标题】如何在 Angular 中为 *ngFor 设置动画?【英文标题】:How can I animate *ngFor in Angular? 【发布时间】:2016-09-10 01:58:29 【问题描述】:我需要在填充和显示ngFor
列表时对其进行动画处理。每个元素都应该有一个过渡,比如说something like this。
我该怎么做?
【问题讨论】:
【参考方案1】:它有一些问题,因为ngFor
做了一些多余的添加/删除,导致项目被动画化,而这不应该:
import Component from 'angular2/core';
import Component, Directive, OnDestroy, Input from 'angular2/core';
@Component(
selector: 'my-app',
template: `<div (click)="$event.preventDefault()">
<button type="button" (click)="pushItem()">Push</button>
<button type="button" (click)="removeItemLast()">Remove Last</button><br/>
<button type="button" (click)="unshiftItem()">Unshift</button>
<button type="button" (click)="removeItemFirst()">Remove First</button><br/>
<ul>
<li class="my-animation" *ngFor="#item of items">
item.title
</li>
</ul>
</div>`
)
export class AppComponent
private count:number = 1;
public items: Array<any>;
constructor()
console.clear();
this.items = [];
this.items.push(this.newItem());
this.items.push(this.newItem());
pushItem()
this.items.push(this.newItem());
,
removeItemLast()
if(this.items.length > 0) this.items.splice(this.items.length - 1, 1);
,
unshiftItem()
this.items.unshift(this.newItem());
,
removeItemFirst()
if(this.items.length > 0) this.items.splice(0, 1);
,
newItem()
return title: 'Item' + this.count++;
@keyframes MyAnimation
0%
padding-left: 100px;
100%
padding-left: 0px;
.my-animation
animation: MyAnimation 1s;
来自https://github.com/angular/angular/issues/7239 的Plunker example (RC.x) 说明了这个问题。
更新
很久以前就修复了
工作Demo on stackblitz
【讨论】:
如何在不改变数组的情况下执行此操作,例如如何使用 Observable> 为插入或更新设置动画 @maxou 我创建了一个新的 Plunker plnkr.co/edit/TMZKPbuzorVt9UsGJ2Nr?p=preview 你可以在这里清楚地看到问题:plnkr.co/edit/Xz48XN?p=preview当你点击'swap'时,所有索引发生变化的项目都会重新添加到dom中,无论'trackBy'子句如何 @JamiePate 当一次更改多个项目时,IterableDiffer 中似乎仍然存在错误。第一次删除,后来添加不会导致两者之间的所有内容都被删除并重新添加plnkr.co/edit/ky0sU4EV5NfXLTCkxC2d?p=preview(虽然后来添加的内容再次动画,但在此设置中是正确的) @GünterZöchbauer 是的,这就是我想要展示的。如果您改用@angular/animations
,它似乎可以正常工作,所以这可能是要走的路。无论如何,对于这种复杂 DOM 交互的动画,动画 web api 比 css 容易得多。 (即使直接使用)【参考方案2】:
现在有guide to Angular's animation system。如果我们想做一些花哨的事情,这很有帮助,比如只为组件初始化后添加的元素做动画,而不是已经存在的元素。我已经修改了以前的答案以使用 Angular 2 方式。
Plunker:http://plnkr.co/edit/NAs05FiAVTlUjDOZfEsF?p=preview
import
Component,
trigger, transition, animate, style, state
from '@angular/core';
@Component(
selector : 'my-app',
animations: [
trigger('growShrinkStaticStart', [
state('in', style( height: '*', 'padding-top': '*', 'padding-bottom': '*', 'margin-top': '*', 'margin-bottom': '*' )),
transition('* => void', [
style( height: '*', 'padding-top': '*', 'padding-bottom': '*', 'margin-top': '*', 'margin-bottom': '*' ),
animate("0.5s ease", style( height: '0', 'padding-top': '0', 'padding-bottom': '0', 'margin-top': '0', 'margin-bottom': '0' ))
]),
transition('void => false', [
/*no transition on first load*/
]),
transition('void => *', [
style( height: '0', 'padding-top': '0', 'padding-bottom': '0', 'margin-top': '0', 'margin-bottom': '0' ),
animate("0.5s ease", style( height: '*', 'padding-top': '*', 'padding-bottom': '*', 'margin-top': '*', 'margin-bottom': '*' ))
])
])
],
template : `<div (click)="$event.preventDefault()">
<button type="button" (click)="pushItem()">Push</button>
<button type="button" (click)="removeItemLast()">Remove Last</button><br/>
<button type="button" (click)="unshiftItem()">Unshift</button>
<button type="button" (click)="removeItemFirst()">Remove First</button><br/>
<ul style="background: light-blue">
<li *ngFor="let item of items"
[@growShrinkStaticStart]="animationInitialized.toString()"
(@growShrinkStaticStart.done)="animationInitialized = true"
style="background-color:pink; border:1px dashed gray; overflow:hidden">
<h3>item.title</h3><p>item.description</p>
</li>
</ul>
<div>Footer</div>
</div>`
)
export class AppComponent
private count: number = 1;
public items: Array < title: string, description: string > ;
private animationInitialized: boolean = false;
constructor()
this.items = [];
this.items.push(this.newItem());
this.items.push(this.newItem());
pushItem()
this.items.push(this.newItem());
removeItemLast()
if (this.items.length > 0)
this.items.splice(this.items.length - 1, 1);
unshiftItem()
this.items.unshift(this.newItem());
removeItemFirst()
if (this.items.length > 0)
this.items.splice(0, 1);
newItem()
let d: string = "";
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz0123456789 . ! ? ";
for (let i = 0; i < Math.floor(Math.random() * 50000); i++)
d += possible.charAt(Math.floor(Math.random() * possible.length));
return title : 'Item' + this.count++, description: d ;
【讨论】:
是否可以使用自定义转场stateChangeExpression
实现相同的转场效果 - 除了void => *
(:entry
) / * => void
(:leave
) for *ngFor
?例如定义transition('in => out',...
和transition('out => in',...
并在模板中使用[@growShrinkStaticStart]="transition"
并绑定到组件类中的transition
变量?我之所以问,是因为 *ngFor
进行了 DOM 添加和删除,而我没有成功通过自定义转换实现这一目标。
嗨,我正在使用 :leave ,如果我返回并刷新并分配一个 api 调用结果,它总是会触发动画。删除一项时是否可以只显示动画?以上是关于如何在 Angular 中为 *ngFor 设置动画?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Angular 中为 ngfor 为 html 模板键入变量?
Angular,如何使用 *ngFor 或 HTML 表的任何重复设置行 ID
单行的Angular6多个ngFor-如何在一个ngFor中传递两个值