使用 Observable 进行渐进式填充

Pie*_*ARD 5 delay observable rxjs debouncing angular

我想使用 Observable<string[]> 在我的 Angular 应用程序的组件上逐渐显示内容。

  1. TypeScript方面我声明了这一点:
export class ResultComponent implements OnInit{
 
 message: string = 'my message for user';
 spreadedMessage$: Observable<string> = from(this.message);
 progressiveMessage:string = "";

 ngOnInit() {
    let interval = 1
    this.obsMessage$
      .pipe(
        tap((letter) => {
           delay(35*interval),
           this.progressiveMessage += letter;
          interval++
        })
      )
      .subscribe();
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 将ProgressiveMessage绑定到模板

<div> {{ progressiveMessage }} </div>

我的完整代码清单可以在这里找到


我尝试了第二种方法,效果很好,如下所示,但我想了解我使用Observable来取得进展有什么问题。

我的替代解决方案:

  1. 变成spreadedMessage$: Observable<string> = from(this.message);spreadedMessage: string[] = [...this.message];

  2. 在方法上声明了这一点OnInit()

for (let i: number = 0; i < this.spreadedMessage.length; i++) {
        setTimeout(() => (this.spaceMessager += this.spreadedMessage[i]), 35 * i);    
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Biz*_*Bob 2

在您的第一个示例代码中,delay()没有执行任何操作!您已将其包含在tap运算符内,这是不正确的。它需要直接位于.pipe().

但是,即使您正确放置它,我认为要让它按照您的意愿工作也很困难,因为不会针对每次发射评估延迟持续时间,而是仅使用初始值评估一次interval

我认为这样的事情起作用:

  ngOnInit() {
    this.spreadedMessage$.pipe(
      concatMap(letter => of(letter).pipe(delay(35))),
      tap(letter => this.progressiveMessage += letter),
    ).subscribe();
  }
Run Code Online (Sandbox Code Playgroud)

在这里,我们为每次发射返回一个新的可观察值concatMap,这允许为每个发射的字母评估延迟间隔。


但是,如果您只是尝试以恒定的时间间隔一次发出一个字符,那么使用interval创建者函数可能会更容易,如下所示:

    interval(35).pipe(
      map(i => this.message[i]),
      take(this.message.length),
      tap(letter => this.progressiveMessage += letter),
    ).subscribe();
Run Code Online (Sandbox Code Playgroud)

由于interval发出从 开始递增的整数,0我们可以使用它作为我们想要发出的字符的索引。

take一旦发送的数量达到消息的长度,我们就使用操作符结束流。


为了进一步简化,我们可以减轻外部变量的影响,只发出我们感兴趣的字符串progressiveMessage部分。message

  ngOnInit() {
    this.spreadedMessage$.pipe(
      concatMap(letter => of(letter).pipe(delay(35))),
      tap(letter => this.progressiveMessage += letter),
    ).subscribe();
  }
Run Code Online (Sandbox Code Playgroud)

而且,如果您想进一步简化,您可以将您的值定义为可观察值并利用async模板中的管道。这消除了订阅和使用ngOnInit

    interval(35).pipe(
      map(i => this.message[i]),
      take(this.message.length),
      tap(letter => this.progressiveMessage += letter),
    ).subscribe();
Run Code Online (Sandbox Code Playgroud)
  interval(35).pipe(
    map(i => this.message.slice(0, i+1)),
    take(this.message.length),
  ).subscribe();
Run Code Online (Sandbox Code Playgroud)

这是一个StackBlitz 的小例子。