angular:传递数据给动画

angular: pass data to animation

我已经为 angular 创建了一个 bootstrap 模态组件,但我想选择模态从哪个方向进入 window。我也 created a StackBlitz 只有最低限度。

目前我的 EnterLeaveAnimation 看起来像这样:

export const EnterLeaveAnimation =
  trigger('enterLeave', [
    transition(
      ':enter', [
        style({ top: '-50%' }), // <-- I should be able to change this dynamically, eg: left: '-50%'
        animate('{{ duration }} ease-in-out', style({ top: 0 })),
      ], {
        params: {
          duration: '500ms'
        }
      }
    ),
    transition(
      ':leave', [
        animate('{{ duration }} ease-in-out', style({ top: '-50%' }))
      ], {
        params: {
          duration: '500ms'
        }
      }
    ),
  ]);

ATM 这个动画应用到 div 像这样:

<div class="modal d-block" [@fadeInOut] [@enterLeave] *ngIf="isOpen">
  <!-- [fromDirection]="fromDirection" -->
  ...
</div>

<div [@fadeInOut] *ngIf="isOpen">
  <div class="modal-backdrop fade" [class.show]="isOpen"></div>
</div>

但最终会寻找 like this:

<div class="modal d-block" [@fadeInOut] [@enterLeave]="{ value: isOpen ? ':enter' : ':leave', params: { fromDirection: fromDirection } }" *ngIf="isOpen">
  ...
</div>

<div [@fadeInOut] *ngIf="isOpen">
  <div class="modal-backdrop fade" [class.show]="isOpen"></div>
</div>

我现在遇到的问题是,我不知道如何在 fromDirection 上将我的 EnterLeaveAnimation 修改为 switch 并相应地应用不同的样式规则:

style({ top: '-50%' })
OR
style({ bottom: '-50%' })
OR
style({ left: '-50%' })
OR
style({ right: '-50%' })

如您所见,我已经将我的 duration 参数传递给动画,但我如何 switch 参数并相应地使用 style 函数?

恐怕你应该“手动”制作动画

别担心,这很简单,看这个 一个简单的例子

有了这个想法,我们可以在你的主机组件中定义一些像

  animate(element: any, state: string, background: boolean) {
    if (element) {
      let customstyle =
        state == 'enter'
          ? background
            ? { opacity: 0 }
            : { top: '-50%', left: '0', opacity: 0 }
          : background
          ? { opacity: 1 }
          : { top: '-100%', left: '0', opacity: 1 };
      if (!background) {
        switch (this.fromDirection) {
          case 'bottom':
            customstyle =
              state == 'enter'
                ? { top: '50%', left: '0', opacity: 0 }
                : { top: '100%', left: '0', opacity: 0 };
            break;
          case 'left':
            customstyle =
              state == 'enter'
                ? { top: '0', left: '-100%', opacity: 0 }
                : { top: '0', left: '-100%', opacity: 0 };
            break;

          case 'right':
            customstyle =
              state == 'enter'
                ? { top: '0', left: '100%', opacity: 0 }
                : { top: '0', left: '100%', opacity: 0 };
            break;
        }
      }
      const myAnimation =
        state == 'enter'
          ? this.builder.build([
              style(customstyle),
              animate(this.timing, style({ top: 0, left: 0, opacity: 1 })),
            ])
          : this.builder.build([animate(this.timing, style(customstyle))]);
      this.player = myAnimation.create(element);
      if (state == 'leave') {
        this.player.onDone(() => {
          this.componentInstance.instance.isOpen = false;
        });
      }
      this.player.play();
    }
  }

您还在宿主组件中定义了一个函数 close

  close() {
    this.isOpen = false;
    this.animate(
      (this.componentInstance.instance as any).modal.nativeElement,
      'leave',
      false
    );
    this.animate(
      (this.componentInstance.instance as any).modalBackground.nativeElement,
      'leave',
      true
    );
  }

并使用getter调用动画

@Input() set isOpen(value: boolean) {
    this._isOpen = value;
    if (this.componentInstance) {
      if (value) {
        this.componentInstance.instance.isOpen = value;
        this.animate(
          (this.componentInstance.instance as any).modal.nativeElement,
          'enter',
          false
        );
        this.animate(
          (this.componentInstance.instance as any).modalBackground
            .nativeElement,
          'enter',
          true
        );
      } else {
        this.animate(
          (this.componentInstance.instance as any).template.nativeElement,
          'leave',
          false
        );
        this.animate(
          (this.componentInstance.instance as any).modalBackground
            .nativeElement,
          'leave',
          true
        );
      }
    }
    this.isOpenChange.emit(value);
  }

如您所见,动画“重新放置”您的动画,但我们可以使用*ngIf到show/hide其他模式[ngClass]在路上

<!---modal.component.html-->
<div #modal [ngClass]="isOpen?'modal d-block':'modal d-none'" class='modal d-block'>
  <div class="modal-dialog">
    <div class="modal-content">
      <ng-container *ngTemplateOutlet="template"></ng-container>
    </div>
  </div>
</div>
<div #modalBackground [ngClass]="isOpen?'d-block':'d-none'">
  <div class="modal-backdrop fade" [class.show]="isOpen"></div>
</div>

看你怎么用模板引用变量来获取背景和内容,所以我们需要用到ViewChild

  @ViewChild('modal') modal:ElementRef
  @ViewChild('modalBackground') modalBackground:ElementRef

注意:在 stackblitz 我对“时间”进行了硬编码,您可以使用 @Input 或其他方式。