You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular父组件中控制多个TypeOut指令的执行顺序?

解决TypeOut指令顺序执行的问题

我来帮你搞定这个文本输出顺序控制的需求!核心思路是用共享服务来统一管理所有TypeOut指令实例,然后父组件通过服务来按顺序触发它们的write方法。下面是一步步的实现方案:

第一步:重构TypeOut服务

我们需要把服务改成一个指令注册中心,负责收集所有指令、排序,并提供按顺序执行的方法:

import { Injectable } from '@angular/core';
import { TypeOutDirective } from './type-out.directive';

@Injectable({
  providedIn: 'root'
})
export class TypeOutService {
  private typeOutDirectives: TypeOutDirective[] = [];

  // 注册指令实例
  registerDirective(directive: TypeOutDirective): void {
    this.typeOutDirectives.push(directive);
    // 按typeOrder排序,确保顺序正确
    this.typeOutDirectives.sort((a, b) => a.order - b.order);
  }

  // 按顺序执行所有指令的write方法
  async executeInOrder(): Promise<void> {
    for (const directive of this.typeOutDirectives) {
      await directive.write();
      // 等待当前指令完成后再执行下一个
    }
  }

  // 可选:清空注册列表(比如组件销毁时调用)
  clearDirectives(): void {
    this.typeOutDirectives = [];
  }
}

第二步:修改TypeOut指令

去掉原来ngAfterViewInit里自动执行的write(),改为注册到服务,并在完成时通知(如果需要的话):

import { Directive, Input, ElementRef, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
import { delay, asyncForEach } from '../async';
import { TypeOutService } from './type-out.service';

@Directive({
  selector: '[typeOut]'
})
export class TypeOutDirective implements OnInit, OnDestroy {
  private dom;
  @Input('typeOut') text: string;
  @Input('typeClump') clump: number = 0; // 设置默认值
  @Input('typeOrder') order: number = 0; // 默认顺序0
  @Input('typeDelay') delay: number = 0; // 默认延迟0
  @Output() finished = new EventEmitter<void>(); // 完成事件
  typeFinished: boolean = false;
  charArr: string[] = [];

  constructor(
    el: ElementRef,
    private typeOutService: TypeOutService // 注入服务
  ) {
    this.dom = el.nativeElement;
    this.dom.innerHTML = '';
  }

  ngOnInit(): void {
    this.charArr = this.text.split('');
    // 注册到服务
    this.typeOutService.registerDirective(this);
  }

  ngOnDestroy(): void {
    // 可选:组件销毁时从服务移除,避免内存泄漏
    // 这里可以扩展服务的remove方法,不过简单场景下clearDirectives在父组件销毁时调用也可
  }

  write = async () => {
    if (this.typeFinished) return; // 避免重复执行
    this.typeFinished = false;
    this.dom.innerHTML = ''; // 执行前清空内容
    let clump = { max: this.clump, current: 0 }
    
    await asyncForEach(this.charArr, async (char) => {
      if (!this.typeFinished) {
        if (clump.current >= clump.max) {
          clump.current = 0;
          await delay(this.delay);
        }
        clump.current++;
        this.dom.innerHTML += char;
      }
    });
    
    this.typeFinished = true;
    this.finished.emit(); // 触发完成事件
  }
}

第三步:修改父组件(app-landing)

在父组件中注入服务,在合适的时机(比如ngAfterViewInit)调用executeInOrder来启动顺序执行:

// landing.component.ts
import { Component, OnInit, AfterViewInit, OnDestroy } from '@angular/core';
import { TypeOutService } from './type-out.service';

@Component({
  selector: 'app-landing',
  templateUrl: './landing.component.html'
})
export class LandingComponent implements AfterViewInit, OnDestroy {
  title = { ascii: '你的标题ASCII', string: '你的标题' };
  subtitle = { ascii: '你的副标题ASCII', string: '你的副标题' };
  portrait = { ascii: '你的肖像ASCII', string: '你的肖像' };

  constructor(private typeOutService: TypeOutService) {}

  ngAfterViewInit(): void {
    // 视图初始化完成后,按顺序执行所有TypeOut指令
    this.typeOutService.executeInOrder();
  }

  ngOnDestroy(): void {
    // 组件销毁时清空服务里的指令列表
    this.typeOutService.clearDirectives();
  }
}

对应的模板部分保持不变,注意typeOrder要设置正确的顺序值,比如:

<h1 class="fontSize1">
  <p style="display:none;">{{title.string}}</p>
  <strong>
    <pre typeOut="{{title.ascii}}" typeClump="10" typeOrder="1" typeDelay="0.1"></pre>
  </strong>
</h1>
<h2 class="fontSize1">
  <p style="display:none;">{{subtitle.string}}</p>
  <pre typeOut="{{subtitle.ascii}}" typeOrder="2" typeDelay="1"></pre>
</h2>
<aside class="portrait">
  <pre class="fontSize2" typeOut="{{portrait.ascii}}" typeClump="10" typeOrder="3" typeDelay="0.1"></pre>
</aside>

关键说明

  • 服务的作用是集中管理所有指令实例,通过registerDirective收集后,按typeOrder排序,确保执行顺序正确。
  • 指令不再自动执行write(),而是等待父组件通过服务触发,这样完全由父组件控制执行时机和顺序。
  • 如果需要在某个指令完成后做额外操作,可以订阅指令的finished事件,或者在服务的executeInOrder中处理。
  • 记得在父组件销毁时调用clearDirectives,避免内存泄漏。

这样改造后,你就能完美控制所有TypeOut指令的文本输出顺序啦!

内容的提问来源于stack exchange,提问作者UC3D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:50:26