javascript - 在动画进行时暂停调度 NgRx Action

标签 javascript angular rxjs css-transitions ngrx

我有一个微型应用程序,它在屏幕上显示一个点。 application screenshot

这是一个简单的 div,绑定(bind)到 NgRx 存储中的状态。

<div class="dot"
   [style.width.px]="size$ | async"
   [style.height.px]="size$ | async"
   [style.backgroundColor]="color$ | async"
   [style.left.px]="x$ | async"
   [style.top.px]="y$ | async"
   (transitionstart)="transitionStart()"
   (transitionend)="transitionEnd()"></div>

点状态的变化由 CSS 转换动画。

.dot {
  border-radius: 50%;
  position: absolute;

  $moveTime: 500ms;
  $sizeChangeTime: 400ms;
  $colorChangeTime: 900ms;
  transition:
    top $moveTime, left $moveTime,
    background-color $colorChangeTime,
    width $sizeChangeTime, height $sizeChangeTime;
}

我有一个后端推送点的更新(位置、颜色和大小)。我将这些更新映射到 NgRx 操作上。

export class AppComponent implements OnInit {
  ...

  constructor(private store: Store<AppState>, private backend: BackendService) {}

  ngOnInit(): void {
    ...

     this.backend.update$.subscribe(({ type, value }) => {
       // TODO: trigger new NgRx action when all animations ended
       if (type === 'position') {
         const { x, y } = value;
         this.store.dispatch(move({ x, y }));
       } else if (type === 'color') {
         this.store.dispatch(changeColor({ color: value }));
       } else if (type === 'size') {
         this.store.dispatch(changeSize({ size: value }));
       }
     });
   }
 }

问题是来自后端的新变化有时比动画结束来得早。 我的目标是延迟更新存储中的状态(暂停触发新的 NgRx 操作)直到所有转换结束。我们可以轻松处理这一刻,因为 chrome 已经支持 transitionstart 事件。

我也可以用这样的图来解释这个 spacing

间距取决于过渡持续时间。

这是可运行的应用程序 https://stackblitz.com/edit/angular-qlpr2g和 repo https://github.com/cwayfinder/pausable-ngrx .

最佳答案

您可以使用 concatMapdelayWhen去做这个。还要注意 transitionEnd 事件 can be fired multiple times如果更改了多个属性,那么我使用 debounceTime过滤此类双重事件。我们不能改用 distinctUntilChanged,因为第一个 transitionEnd 将触发下一次更新,立即将 transitionInProgress$ 状态更改为 true。我不使用 transitionStart 回调,因为在触发 transitionStart 之前可能会出现多个更新。 Here is工作示例。

export class AppComponent implements OnInit {
  ...

  private readonly  transitionInProgress$ = new BehaviorSubject(false);

  ngOnInit(): void {
    ...

    this.backend.update$.pipe(
      concatMap(update => of(update).pipe(
        delayWhen(() => this.transitionInProgress$.pipe(
          // debounce the transition state, because transitionEnd event fires multiple
          // times for a single transiation, if multiple properties were changed
          debounceTime(1),
          filter(inProgress => !inProgress)
        ))
      ))
    ).subscribe(update => {
        this.transitionInProgress$.next(true)

        if (update.type === 'position') {
          this.store.dispatch(move(update.value));
        } else if (update.type === 'color') {
          this.store.dispatch(changeColor({ color: update.value }));
        } else if (update.type === 'size') {
          this.store.dispatch(changeSize({ size: update.value }));
        }
    });
  }

  transitionEnd(event: TransitionEvent) {
    this.transitionInProgress$.next(false)
  }
}

关于javascript - 在动画进行时暂停调度 NgRx Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57026990/

相关文章:

Angular 4 - 过滤时将 HTTP 请求限制为每 200 毫秒一次

javascript - Jquery 侧边栏在 IE 中不起作用

RxJS 缓冲直到改变

javascript - 如何触发一个 promise ,然后用 $q 触发第二个 promise ?

javascript - Angular 2 API 服务显示错误 UI 消息

javascript - Angular http 服务循环

angular - 禁用选定的下拉选项 Angular 2?

javascript - 组合多个可管道化的 NgRx 选择器

javascript - 添加 header 来获取,解决cors,运行cryptojs客户端

javascript - Google Maps API - 在从 ajax 页面加载新数据之前清除标记、多段线