Angular Directive如何实现导航后不重执行 仅在页面首次加载时运行
解决方案
路由导航时关联组件会销毁重建,绑定的指令也会重新触发初始化生命周期,是动画重复执行的核心原因。可以通过全局单例状态存储动画执行标记的方式实现仅初始加载执行的需求,具体修改如下:
步骤1:创建全局单例标记服务
这个服务会在整个应用生命周期内保留状态,不会随路由切换销毁:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class AnimationFlagService { // 支持多动画元素独立控制,用Set存储各元素的唯一执行标记 private executedAnims = new Set<string>(); checkAnimated(animId: string): boolean { return this.executedAnims.has(animId); } markAnimated(animId: string): void { this.executedAnims.add(animId); } }
步骤2:修改原指令逻辑
新增可选的动画ID输入,初始化时先判断动画是否已经执行过:
@Directive({ selector: '[appAnimateText]' }) export class AnimateTextDirective implements AfterViewInit, OnInit { // 动画元素唯一标识,单元素场景可不传,用默认值即可 @Input() animId = 'default-text-anim'; @HostBinding('style.white-space') whiteSpace = 'pre'; private animateTo: string | undefined; constructor( private el: ElementRef, private animFlagService: AnimationFlagService ) {} get innerText(): string { return this.el.nativeElement.innerText; } set innerText(newText: string) { this.el.nativeElement.innerText = newText; } ngOnInit(): void { // 已执行过动画则直接保留原文本,不做占位符替换 if (this.animFlagService.checkAnimated(this.animId)) { return; } this.animateTo = this.innerText; this.innerText = this.innerText.split('').map(() => ' ').join(''); } ngAfterViewInit(): void { if (this.animFlagService.checkAnimated(this.animId)) { return; } if (this.animateTo) { this.animate(this.animateTo.split('')).then(() => { // 动画执行完成后标记为已执行 this.animFlagService.markAnimated(this.animId); }); } } animate(animateTo: string[]): Promise<void> { // 保留原有动画逻辑即可 return new Promise((res) => setTimeout(res, 2000)) } }
模板使用示例
<!-- 单个动画元素 --> <div appAnimateText>要展示的动画文本</div> <!-- 多个独立控制的动画元素,传入不同ID即可 --> <div appAnimateText animId="header-text">头部动画文本</div> <div appAnimateText animId="banner-text">横幅动画文本</div>
备选扩展方案
如果需要页面刷新后也不重复执行动画,可以把标记存储到sessionStorage或localStorage中,替换掉服务里的Set存储逻辑即可。
内容的提问来源于stack exchange,提问作者Vincent Menzel
相关产品推荐
相关产品推荐

