从 ngFor 中删除元素时,如何在 Angular 7 中使用退出动画?
How do I utilize an exit animation in Angular 7 when removing an element from ngFor?
我正在尝试从 Observable 数组中删除一个元素并使用退出动画。进入动画效果很好,但是退出动画根本不会触发,元素会突然被删除。我在下面包含了我的代码。感谢任何帮助或建议!
ao-notifications.service.ts
import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject, timer } from 'rxjs';
import * as _ from 'lodash';
import Message from '../dependencies/Message';
import MessageOptions from '../dependencies/MessageOptions';
@Injectable({
providedIn: 'root'
})
export class AoNotificationsService {
id: BehaviorSubject<number> = new BehaviorSubject<number>(0);
messages: BehaviorSubject<Message[]> = new BehaviorSubject<Message[]>([]);
list(): Observable<Message[]> {
return this.messages;
}
emit({ content, style, delay }: MessageOptions) {
const id = this.id.getValue();
const message = new Message(id, content, style);
this.messages.next(_.sortBy(_.concat(this.messages.getValue(), message), (o: Message) => o.id).reverse());
if (delay) {
timer(delay).subscribe(() => this.purge(id));
}
this.id.next(id + 1);
}
purge(id: number) {
this.messages.next(_.filter(this.messages.getValue(), o => o.id !== id));
}
}
ao-notifications.component.html
<div class="wrapper">
<aside *ngFor="let message of (messages | async)">
<div
@messageState
class="notification"
[ngClass]="{
primary: message.style == 'primary',
secondary: message.style == 'secondary',
success: message.style == 'success',
danger: message.style == 'danger',
warning: message.style == 'warning',
info: message.style == 'info'
}"
>
<button class="dismiss" (click)="dismiss(message.id)">X</button> {{ message.content }}
</div>
</aside>
</div>
ao-notifications.component.ts
import { Component, OnInit } from '@angular/core';
import { trigger, style, animate, transition } from '@angular/animations';
import { Observable } from 'rxjs';
import Message from './dependencies/Message';
import { AoNotificationsService } from './services/ao-notifications.service';
@Component({
selector: 'ao-notifications',
templateUrl: './ao-notifications.component.html',
styleUrls: ['./ao-notifications.component.scss'],
animations: [
trigger('messageState', [
transition('void => *', [
style({
opacity: 0
}),
animate(
'1s ease-in-out',
style({
opacity: 1
})
)
]),
transition('* => void', [
animate(
'1s ease-in-out',
style({
opacity: 0
})
)
])
])
]
})
export class AoNotificationsComponent implements OnInit {
messages: Observable<Message[]>;
constructor(private notifications: AoNotificationsService) {}
ngOnInit() {
this.messages = this.notifications.list();
}
dismiss(id: number) {
this.notifications.purge(id);
}
}
问题是因为 *ngFor 在旁边,而不是在调用 @messageState 的 div 上。如果像下面这样修改,动画就可以正常工作了。
<div class="wrapper">
<aside>
<div
*ngFor="let message of (messages | async)" <!-- Fixed Here -->
@messageState
class="notification"
[ngClass]="{
primary: message.style == 'primary',
secondary: message.style == 'secondary',
success: message.style == 'success',
danger: message.style == 'danger',
warning: message.style == 'warning',
info: message.style == 'info'
}"
>
<button class="dismiss" (click)="dismiss(message.id)">X</button> {{ message.content }}
</div>
</aside>
</div>
我正在尝试从 Observable 数组中删除一个元素并使用退出动画。进入动画效果很好,但是退出动画根本不会触发,元素会突然被删除。我在下面包含了我的代码。感谢任何帮助或建议!
ao-notifications.service.ts
import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject, timer } from 'rxjs';
import * as _ from 'lodash';
import Message from '../dependencies/Message';
import MessageOptions from '../dependencies/MessageOptions';
@Injectable({
providedIn: 'root'
})
export class AoNotificationsService {
id: BehaviorSubject<number> = new BehaviorSubject<number>(0);
messages: BehaviorSubject<Message[]> = new BehaviorSubject<Message[]>([]);
list(): Observable<Message[]> {
return this.messages;
}
emit({ content, style, delay }: MessageOptions) {
const id = this.id.getValue();
const message = new Message(id, content, style);
this.messages.next(_.sortBy(_.concat(this.messages.getValue(), message), (o: Message) => o.id).reverse());
if (delay) {
timer(delay).subscribe(() => this.purge(id));
}
this.id.next(id + 1);
}
purge(id: number) {
this.messages.next(_.filter(this.messages.getValue(), o => o.id !== id));
}
}
ao-notifications.component.html
<div class="wrapper">
<aside *ngFor="let message of (messages | async)">
<div
@messageState
class="notification"
[ngClass]="{
primary: message.style == 'primary',
secondary: message.style == 'secondary',
success: message.style == 'success',
danger: message.style == 'danger',
warning: message.style == 'warning',
info: message.style == 'info'
}"
>
<button class="dismiss" (click)="dismiss(message.id)">X</button> {{ message.content }}
</div>
</aside>
</div>
ao-notifications.component.ts
import { Component, OnInit } from '@angular/core';
import { trigger, style, animate, transition } from '@angular/animations';
import { Observable } from 'rxjs';
import Message from './dependencies/Message';
import { AoNotificationsService } from './services/ao-notifications.service';
@Component({
selector: 'ao-notifications',
templateUrl: './ao-notifications.component.html',
styleUrls: ['./ao-notifications.component.scss'],
animations: [
trigger('messageState', [
transition('void => *', [
style({
opacity: 0
}),
animate(
'1s ease-in-out',
style({
opacity: 1
})
)
]),
transition('* => void', [
animate(
'1s ease-in-out',
style({
opacity: 0
})
)
])
])
]
})
export class AoNotificationsComponent implements OnInit {
messages: Observable<Message[]>;
constructor(private notifications: AoNotificationsService) {}
ngOnInit() {
this.messages = this.notifications.list();
}
dismiss(id: number) {
this.notifications.purge(id);
}
}
问题是因为 *ngFor 在旁边,而不是在调用 @messageState 的 div 上。如果像下面这样修改,动画就可以正常工作了。
<div class="wrapper">
<aside>
<div
*ngFor="let message of (messages | async)" <!-- Fixed Here -->
@messageState
class="notification"
[ngClass]="{
primary: message.style == 'primary',
secondary: message.style == 'secondary',
success: message.style == 'success',
danger: message.style == 'danger',
warning: message.style == 'warning',
info: message.style == 'info'
}"
>
<button class="dismiss" (click)="dismiss(message.id)">X</button> {{ message.content }}
</div>
</aside>
</div>