Angular 动画:错开动画子组件
Angular animation: stagger animate child components
几天来,我一直在努力让 Angular 动画为子组件(Content Children)工作,但尽管阅读了我能找到的所有内容,但我无法让它工作。
这个问题似乎大致在做我想做的事情,但我无法让它工作:
StackBlitz:https://stackblitz.com/edit/angular-anim-children
我的组件是:
父组件
import { Component } from '@angular/core';
import { trigger, transition, style, animate, query, stagger, group, animateChild } from '@angular/animations';
import { ListService } from '../services/list.service';
@Component({
selector: 'app-list-container',
template: `
<button (click)="add()">Add</button>
<hr>
<app-list-item
*ngFor="let item of list$ | async; let idx = index;"
(delete)="remove(idx)"
[@list]="(list$ | async).length"
[title]="item.title"
[index]="idx"
></app-list-item>
`,
styles: [`
:host {
display: block;
}
`],
animations: [
trigger('list', [
transition('* => *', [
query(':enter', stagger(50, animateChild()), { optional: true })
])
])
]
})
export class ListContainerComponent {
readonly list$ = this.listService.list;
readonly index: number;
constructor(
private readonly listService: ListService,
) { }
add(): void {
const counter = this.listService.counter;
this.listService.add({ title: `Item ${counter + 1}` });
}
remove(index: number): void {
this.listService.remove(index);
}
}
子组件
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { trigger, transition, style, animate, query, stagger } from '@angular/animations';
@Component({
selector: 'app-list-item',
template: `
<div class="list-item" [@animate]="true">
{{title}}
<button (click)="onDelete(index)">Delete</button>
</div>
`,
styles: [
`
:host {
display: block;
}
button {
margin-left: 20px;
}
`
],
animations: [
trigger('animate', [
transition(':enter', [
style({ opacity: 0, transform: 'translateX(-10px)' }),
animate('250ms', style({ opacity: 1, transform: 'translateX(0px)' }))
]),
transition(':leave', [
style({ opacity: 1 }),
animate('250ms', style({ opacity: 0, transform: 'translateX(10px)' }))
])
])
],
})
export class ListItemComponent {
@Input() title: string;
@Input() index: number;
@Output() delete = new EventEmitter<number>();
onDelete(index: number): void {
this.delete.emit(index);
}
}
服务
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
export interface IItem {
title: string,
}
@Injectable()
export class ListService {
private readonly _list = new BehaviorSubject<IItem[]>([]);
readonly list = this._list.asObservable();
counter = 0;
get length() {
return this._list.value.length;
}
add(item: IItem): void {
this._list.next([item, ...this._list.value]);
this.counter += 1;
}
remove(index: number): void {
this._list.value.splice(index, 1);
}
clear(): void {
this._list.next([]);
}
}
您有一些错误,首先,父级动画(list
动画)应如下所示:
trigger("list", [
transition("* => *", [query("@animate", stagger(50, animateChild()))])
])
请注意,您需要查询子动画才能错开它。
您应该将它添加到具有 animate
动画的元素的父元素上,因此在 list-container.component.ts
的模板中类似以下内容:
<div @list>
<app-list-item
*ngFor="let item of (list$ | async); let idx = index"
(delete)="remove(idx)"
[title]="item.title"
[index]="idx"
></app-list-item>
</div>
[@animate]="true"
可以变成@animate
(这不是错误,而是多余的)
这是一个有效的 stackblitz
几天来,我一直在努力让 Angular 动画为子组件(Content Children)工作,但尽管阅读了我能找到的所有内容,但我无法让它工作。
这个问题似乎大致在做我想做的事情,但我无法让它工作:
StackBlitz:https://stackblitz.com/edit/angular-anim-children
我的组件是:
父组件
import { Component } from '@angular/core';
import { trigger, transition, style, animate, query, stagger, group, animateChild } from '@angular/animations';
import { ListService } from '../services/list.service';
@Component({
selector: 'app-list-container',
template: `
<button (click)="add()">Add</button>
<hr>
<app-list-item
*ngFor="let item of list$ | async; let idx = index;"
(delete)="remove(idx)"
[@list]="(list$ | async).length"
[title]="item.title"
[index]="idx"
></app-list-item>
`,
styles: [`
:host {
display: block;
}
`],
animations: [
trigger('list', [
transition('* => *', [
query(':enter', stagger(50, animateChild()), { optional: true })
])
])
]
})
export class ListContainerComponent {
readonly list$ = this.listService.list;
readonly index: number;
constructor(
private readonly listService: ListService,
) { }
add(): void {
const counter = this.listService.counter;
this.listService.add({ title: `Item ${counter + 1}` });
}
remove(index: number): void {
this.listService.remove(index);
}
}
子组件
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { trigger, transition, style, animate, query, stagger } from '@angular/animations';
@Component({
selector: 'app-list-item',
template: `
<div class="list-item" [@animate]="true">
{{title}}
<button (click)="onDelete(index)">Delete</button>
</div>
`,
styles: [
`
:host {
display: block;
}
button {
margin-left: 20px;
}
`
],
animations: [
trigger('animate', [
transition(':enter', [
style({ opacity: 0, transform: 'translateX(-10px)' }),
animate('250ms', style({ opacity: 1, transform: 'translateX(0px)' }))
]),
transition(':leave', [
style({ opacity: 1 }),
animate('250ms', style({ opacity: 0, transform: 'translateX(10px)' }))
])
])
],
})
export class ListItemComponent {
@Input() title: string;
@Input() index: number;
@Output() delete = new EventEmitter<number>();
onDelete(index: number): void {
this.delete.emit(index);
}
}
服务
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
export interface IItem {
title: string,
}
@Injectable()
export class ListService {
private readonly _list = new BehaviorSubject<IItem[]>([]);
readonly list = this._list.asObservable();
counter = 0;
get length() {
return this._list.value.length;
}
add(item: IItem): void {
this._list.next([item, ...this._list.value]);
this.counter += 1;
}
remove(index: number): void {
this._list.value.splice(index, 1);
}
clear(): void {
this._list.next([]);
}
}
您有一些错误,首先,父级动画(list
动画)应如下所示:
trigger("list", [
transition("* => *", [query("@animate", stagger(50, animateChild()))])
])
请注意,您需要查询子动画才能错开它。
您应该将它添加到具有 animate
动画的元素的父元素上,因此在 list-container.component.ts
的模板中类似以下内容:
<div @list>
<app-list-item
*ngFor="let item of (list$ | async); let idx = index"
(delete)="remove(idx)"
[title]="item.title"
[index]="idx"
></app-list-item>
</div>
[@animate]="true"
可以变成@animate
(这不是错误,而是多余的)
这是一个有效的 stackblitz