Angular如何检测动画完成?@animation.done初始意外触发问题
Angular @animation.done 初始化阶段提前触发的解决方法
问题本质
Angular 动画的@triggerName.done事件会在所有动画状态流转完成时触发,并非仅响应主动触发的显式动画:
- 组件初始化、元素首次挂载时,会执行一次从
void(元素不存在状态)到初始绑定状态的隐式状态流转,哪怕你没有配置void状态的动画,这次流转完成后也会立刻触发done事件,这就是初始化阶段回调提前执行、甚至早于预期动画开始的核心原因。 - 所有显式触发的状态切换(比如示例中
in/out状态互切)、零时长状态跳转完成后,同样会触发该事件。
可直接落地的解决方法
方法1:通过事件参数过滤无效触发
done回调的入参是AnimationEvent类型,自带状态流转的上下文信息,通过判断fromState、toState字段即可精准过滤出你需要监听的动画完成场景:
- 先在TS文件顶部引入类型:
import { AnimationEvent } from '@angular/animations'; - 修改回调逻辑,跳过初始化阶段的隐式触发:
HTML模板部分的绑定不需要修改,保持原有写法即可:animationDone(event: AnimationEvent) { // 跳过初始化阶段从void状态开始的首次流转 if (event.fromState === 'void') { return; } // 如果只需要监听特定状态的动画完成,可再加一层判断,比如只处理入场动画结束 if (event.toState === 'in') { // 此处写动画结束后要执行的业务逻辑 console.log('目标动画执行完成', this.viewProjectState); } }<button type="button" class="button-viewproject" [@fadeInUpViewProject]="viewProjectState ? 'in' : 'out'" (@fadeInUpViewProject.done)="animationDone($event)" > View Me </button>
方法2:用标记位跳过初始化阶段触发
如果业务逻辑只需要响应用户交互触发的动画,不需要处理首次加载的动画,可以加组件级标记位过滤:
// 组件类中添加标记 private isFirstAnimationSkipped = false; // 在你切换viewProjectState状态的方法中,首次触发交互时更新标记 toggleProjectState() { this.viewProjectState = !this.viewProjectState; this.isFirstAnimationSkipped = true; } animationDone(event: AnimationEvent) { if (!this.isFirstAnimationSkipped) { return; } // 此处写动画完成后的业务逻辑 }
注意事项
不要在done回调中通过硬编码setTimeout延时等待动画,done事件本身的触发时机和动画定义中配置的时长完全对齐,初始化提前触发的问题本质是没有过滤隐式状态流转的事件,不是事件本身时机不准。
内容的提问来源于stack exchange,提问作者Snorlax
相关产品推荐
相关产品推荐

