【问题标题】:Angular2: How do you run 2 animations in parallel?Angular2:你如何并行运行 2 个动画?
【发布时间】:2017-08-27 12:07:06
【问题描述】:

我有一个可以扩展/收缩的容器。该容器内有一个元素,该元素应在容器扩展时淡入,在容器收缩时淡出。

我的问题

  • 当容器展开时,两个元素的动画都会起作用。
  • 当容器缩小时,只有容器动画起作用。
  • 如果我删除了容器展开动画,那么淡入/淡出动画会按预期工作。

如何让所有动画在两种展开/收缩条件下并行执行?

注意 ngIf 的使用。这是故意的,因为它会在动画序列结束时破坏元素。

这是我当前状态的一个小插曲: https://embed.plnkr.co/TXYoGf9QpErWmlRvQF9Z/

组件类:

export class App {
  expanded = true;

  toggleExpandedState() {
    this.expanded = !this.expanded;
  }

  constructor() {
  }
}

模板:

<div class="container" [@expansionTrigger]="expanded">
  <div class="constant-item"></div>
  <div class="fade-item" [@stateAnimation] *ngIf="expanded"></div>
</div>

<button (click)="toggleExpandedState()">Toggle Fade</button>

以及组件动画:

  trigger('expansionTrigger', [
    state('1', style({
      width: '250px'
    })),
    state('0', style({
      width: '160px'
    })),
    transition('0 => 1', animate('200ms ease-in')),
    transition('1 => 0', animate('200ms ease-out'))
  ]),
  trigger('stateAnimation', [
    transition(':enter', [
      style({
        opacity: 0
      }),
      animate('200ms 350ms ease-in', style({
        opacity: 1
      }))
    ]),
    transition(':leave', [
      style({
        opacity: 1
      })
      animate('1s', style({
        opacity: 0
      }))
    ])
  ])

【问题讨论】:

标签: angular typescript angular-ng-if


【解决方案1】:

为了避免其他人的挫败感,看起来这是 Angular 4 的一个错误。

Github 上目前有两个未决问题似乎密切相关:

https://github.com/angular/angular/issues/15798

https://github.com/angular/angular/issues/15753

更新

根据 github 问题,动画错误不会像以前在 Angular2 中那样修复。而是引入了query()animateChild()。从 4.2.0-rc2 开始提供新的动画功能。

总结:

组件定义

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <button (click)="toggle()">Toggle</button>
      <div *ngIf="show" @ngIfAnimation>
        <h3 @easeInOut>I'm inside ngIf</h3>
      </div>
    </div>
  `,
animations: [
  trigger('ngIfAnimation', [
    transition(':enter, :leave', [
      query('@*', animateChild())
    ])
  ])
  trigger('easeInOut', [
    transition('void => *', [
        style({
            opacity: 0
        }),
        animate("1s ease-in-out", style({
            opacity: 1
        }))
    ]),
    transition('* => void', [
        style({
            opacity: 1
        }),
        animate("1s ease-in-out", style({
            opacity: 0
        }))
    ])
  ])
]]

})
export class App {
  name:string;
  show:boolean = false;

  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }

  toggle() {
    this.show = !this.show;
  }
}

这里有一个工作示例:https://embed.plnkr.co/RJgAunJfibBKNFt0DCZS/

【讨论】:

    【解决方案2】:

    这是你需要做的:

    请戳这里:https://plnkr.co/edit/AQEVh3GGc31ivQZMp223?p=preview

    删除*ngIf="expanded"使用[@stateAnimation]="expanded"

    用这个替换你的stateAnimate触发器:

    trigger('stateAnimation', [
              state('1', style({ opacity: 0 })),
              state('0', style({opacity: 1})),
              transition('0 => 1', animate('200ms ease-in')),
              transition('1 => 0', animate('200ms ease-out'))
            ])
    

    这里是完整的代码:

    //our root app component
    import {Component, NgModule, VERSION, 
      Output,
      trigger,
      state,
      style,
      transition,
      animate,
    } from '@angular/core'
    import {BrowserModule} from '@angular/platform-browser'
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    
    @Component({
      selector: 'my-app',
      template: `
        <div class="container" [@expansionTrigger]="expanded">
          <div class="constant-item"></div>
          <div class="fade-item" [@stateAnimation]="expanded"></div>
        </div>
    
        <button (click)="toggleExpandedState()">Toggle Fade</button>
      `,
      animations: [
        trigger('expansionTrigger', [
          state('1', style({ width: '250px' })),
          state('0', style({width:'160px'})),
          transition('0 => 1', animate('200ms ease-in')),
          transition('1 => 0', animate('200ms ease-out'))
        ]),
        trigger('stateAnimation', [
          state('1', style({ opacity: 0 })),
          state('0', style({opacity: 1})),
          transition('0 => 1', animate('200ms ease-in')),
          transition('1 => 0', animate('200ms ease-out'))
        ])
      ]
    })
    export class App {
      expanded = true;
    
      toggleExpandedState() {
        this.expanded = !this.expanded;
      }
    
      constructor() {
      }
    }
    
    @NgModule({
      imports: [ BrowserModule, BrowserAnimationsModule ],
      declarations: [ App ],
      bootstrap: [ App ]
    })
    export class AppModule {}
    

    【讨论】:

    • 嗨,艾哈迈德——感谢您的回答。不幸的是,该方法不会破坏 'fade-item' 元素。这就是在这里创造挑战的原因。
    • 所以你想销毁淡入淡出项目?您从未在问题中提及这一点。请更新您的问题,详细说明您的期望。
    • 已更新。谢谢。沿着这些思路,我正在寻找一个 Angular2 解决方案。模拟被破坏元素的 CSS 黑客技术不起作用。
    • @axlj 我真的很好奇你为什么要销毁元素?无论如何,你可能对上面的代码和动画回调 .start.done 在这里描述:angular.io/docs/ts/latest/guide/… 有一些运气。这与 AfterViewChecked 的某些组件更改检测侦听器在 fade-item 的构造之后或相反在其销毁之前执行动画。
    • 再次感谢您的帮助。我将看一下开始/完成事件。这个问题是我想要实现的一个非常简化的用例。我正在将多媒体桌面应用程序移植到网络上。销毁元素解决了一系列问题,其中主要是 (1) 最大限度地减少资源需求和 (2) 避免使用无关的 CSS 来实现相同的用户体验。
    猜你喜欢
    • 2021-11-25
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    • 2019-09-18
    • 2015-08-23
    • 2020-10-15
    • 2022-01-14
    • 1970-01-01
    相关资源
    最近更新 更多