首页 > 解决方案 > 以编程方式角度动画,如何在 ngOnDestroy 之前调用动画生成器以进行离开动画

问题描述

在 html 中,我有 ngIf 来控制显示或销毁抽屉组件。我想使用 AnimationBuilder 为抽屉动态调用我的动画。所以我在父组件(应用程序组件)中使用了动画生成器,它在将 slideIn 动画应用于抽屉时效果很好。但是当抽屉组件从 DOM 移开时,我想应用 slideOut 动画。它不起作用,因为在我的动画完成之前调用了 ngOnDestroy。

请注意,我知道:leave :enter可能会起作用,但我想知道这是否可以专门与 AnimationBuilder 一起使用。问题是我不知道如何在 ngOnDestroy 之前播放动画。

这是带有 ngIf 的 html 来控制显示或销毁抽屉

<app-drawer #drawer *ngIf="showDrawer"></app-drawer>

我的应用组件

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnInit, OnDestroy {
  title = 'angular-test';
  showDrawer = false;
  // @ts-ignore
  player: AnimationPlayer;

  // @ts-ignore
  @ViewChild('drawer', { read: ElementRef }) drawer: ElementRef;

  constructor(
    private animationBuilder: AnimationBuilder,
    private cdr: ChangeDetectorRef
  ) {}

  toggleDrawer(): void {
    this.showDrawer = !this.showDrawer;
    this.runSlideAnimation(this.showDrawer);
  }

  runSlideAnimation(showDrawer: boolean): void {
    if (showDrawer) {
      // to make sure element is on dom by ngIf change before I apply animation
      this.cdr.detectChanges();
    }
    if (this.player) {
      this.player.destroy();
    }
    const factory = this.animationBuilder.build(
      showDrawer ? slideInAnimation : slideOutAnimation
    );
    this.player = factory.create(this.drawer.nativeElement);
    this.player.play();
    // My thoughts was manually update dom when slideout animation finish so angular will call
    // ngOndestroy after my animation is done. it didn't work
    this.player.onDone(() => {
      this.cdr.detectChanges();
    });
  }

  ngOnInit(): void {
    console.log('init');
  }

  ngOnDestroy(): void {
    if (this.player) {
      this.player.destroy();
    }
    console.log('destroy');
  }

  get slideInAnimation() {
    return [
      style({ opacity: 0, transform: 'translateX(100%)' }),
      animate('600ms', style({ opacity: 1, transform: 'translateX(0)' })),
    ];
  }

  get slideOutAnimation() {
    return [
      style({ opacity: 1, transform: 'translateX(0)' }),
      animate('900ms', style({ opacity: 0, transform: 'translateX(100%)' })),
    ];
  }
}

标签: angularanimation

解决方案


我想你可以使用二传手

_showDrawer:boolean
get showDrawer(){
  return this._showDrawer;
}
set showDrawer(value){
  if (!value){
    this.runSlideAnimation(value,true)
  }
  else
    this._showDrawer=value
}

而你的函数 runSlideAnimation

runSlideAnimation(showDrawer: boolean,forceDestroy:boolean=false){
    ...
    this.player.onDone(() => {
      if (forceDestroy)
          this._showDrawer=false
      this.cdr.detectChanges();
    });
}

推荐阅读