所以我有一个待办事项列表,每个待办事项都有波纹,当您单击待办事项时,我想将页面路由到新的URL,但我希望在此之前完成波纹动画。
在Angular 4+中,我找不到轻松实现此目标的方法,到目前为止,我提出的唯一解决方案是以下解决方案,在Angular中是否存在“正确”的实现方法?
组件:
export class TodoListComponent {
public todos = this.todoService.todos$;
@ViewChildren(MatRipple) private ripples: QueryList<MatRipple>;
constructor(private todoService: TodoService, private router: Router) {}
public onGoTo(event: MouseEvent, index: number, todo: Todo): void {
const enterDuration = 300;
const exitDuration = 50;
const rippleRef = this.ripples
.toArray()
[index].launch(event.clientX, event.clientY, {
animation: {
enterDuration,
exitDuration,
},
});
setTimeout(() => rippleRef.fadeOut, enterDuration);
const animationDuration = enterDuration + exitDuration;
setTimeout(() => this.router.navigate([todo.id]), animationDuration);
}
}
模板:
<mat-list>
<mat-list-item
*ngFor="let todo of (todos | async); let index = index"
mat-ripple
[matRippleDisabled]="true"
>
<div class="Todo">
<div class="Todo__Label" (click)="onGoTo($event, index, todo)">
{{ todo.title }}
</div>
</div>
</mat-list-item>
</mat-list>
答案 0 :(得分:1)
在Angular 4+中,我找不到轻松实现此目标的方法,到目前为止,我提出的唯一解决方案是以下解决方案,在Angular中是否存在“正确”的实现方法?
不,没有Angular方式,因为MatRipple组件不是以Angular方式完成的。波纹效果是由RippleRenderer手动管理的,它看起来不像使用Angular动画。
https://github.com/angular/material2/blob/master/src/lib/core/ripple/ripple-renderer.ts
const rippleRef = this.ripples
.toArray()
[index].launch(event.clientX, event.clientY, {
animation: {
enterDuration,
exitDuration,
},
});
通过启动返回的RippleRef对象将告诉您波纹的当前状态。 RippleRenderer执行动画时,有一个rippleRef.state
属性会随着时间的变化而变化。
https://github.com/angular/material2/blob/master/src/lib/core/ripple/ripple-ref.ts
您可以尝试将波纹动画结束时发出的可观察物体归为一体,但是您唯一的其他选择是使用setTimeout()
。
interval(100)
.pipe(
map(()=>rippleRef.state),
distinctUntilChanged(),
filter(state=>state === RippleState.HIDDEN),
first()
).subscribe(()=> {
console.log('ripple animation finished');
});
我不确定上面的方法是否会起作用,因为第一个状态为HIDDEN,然后又转换回HIDDEN。我假设interval(100)
将跳过第一个“隐藏”状态。
答案 1 :(得分:0)
Angular支持@animation.start
和@animation.done
来参与动画事件。
例如,您可以使用
(@routeAnimation.start)=onStart($event)
和(@routeAnimation.done)=onDone($event)
在您的组件中。
希望获得帮助!
示例代码:
import { Component, OnInit } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/core';
@Component({
selector: 'app-first',
template: `
<div class="w9914420" [@routeAnimation]="show"
(@routeAnimation.start)="onStart($event)"
(@routeAnimation.done)="onDone($event)">
<h2>
first-component Works!
</h2>
</div>
`,
host: {
'[@routeAnimation]': 'true',
'[style.display]': "'block'",
'[style.position]': "'absolute'"
},
animations: [
trigger('routeAnimation', [
state('*', style({transform: 'translateX(0)', opacity: 1})),
transition('void => *', [style({transform: 'translateX(-100%)', opacity: 0}),animate(500)]),
transition('* => void', animate(500, style({transform: 'translateX(100%)', opacity: 0})))
])
]
})
export class FirstComponent implements OnInit {
constructor() { }
ngOnInit() {
}
onStart($event) {
// call this function at start of the animation.
console.log('starting animation');
}
onDone($event) {
// call this function at the end of the animation.
console.log('the end of the animation');
}
}