如何在 Angular 中有条件地动画 :enter & :leave 过渡?

akc*_*soy 6 angular angular-animations

我有一个列表,其中的项目有这样的动画:

<li @animation>
Run Code Online (Sandbox Code Playgroud)

这是我的动画触发器:

trigger('animation', [
  transition(':enter', [
    style({ height: '0px', 'padding-top': '0', 'padding-bottom': '0'}),  // initial
    animate('0.5s',
      style({ height: '*', 'padding-top': '*', 'padding-bottom': '*'}))  // final
  ]),
  transition(':leave', [
    style({ height: '*', 'padding-top': '*', 'padding-bottom': '*', opacity: 1}),  // initial
    animate('0.5s',
      style({ height: '0px', 'padding-top': '0', 'padding-bottom': '0', opacity: 0}))  // final
  ])
])
Run Code Online (Sandbox Code Playgroud)

如何有条件地为特定项目打开/关闭此动画?其实我在找…… 像这样:

<li [@animation]=item.isAnimated>
Run Code Online (Sandbox Code Playgroud)

这根本不起作用。

不幸的是,Angular 文档对此只有一句话:

对于进入或离开页面(从 DOM 中插入或删除)的元素,您可以使动画有条件。例如,将 *ngIf 与 HTML 模板中的动画触发器一起使用。

但是当我将动画注释与 *ngIf 结合起来时,非动画项目显然根本不会显示:

<li *ngIf="item.isAnimated" @animation>
Run Code Online (Sandbox Code Playgroud)

无论 isAnimated 标志如何,我都想进一步显示所有项目。我只想打开/关闭特定项目的动画。

j4r*_*rey 7

根据Angular IO

当为 true 时,特殊动画控件绑定 @.disabled 绑定会阻止所有动画渲染。将 @.disabled 绑定放在元素上以禁用元素本身的动画以及元素内的任何内部动画触发器。

以下示例显示了如何使用此功能:

@Component({
    selector: 'my-component',
    template: `
    <div [@.disabled]="isDisabled">
        <div [@childAnimation]="exp"></div>
    </div>
    `,
    animations: [
        trigger("childAnimation", [
            // ...
        ])
    ]
})
class MyComponent {
      isDisabled = true;
  exp = '...';
}
Run Code Online (Sandbox Code Playgroud)

当@.disabled 为true 时,它​​会阻止@childAnimation 触发器以及任何内部动画进行动画处理。


Sim*_*ver 5

创建一个无操作动画触发器并将其插入之前:enter

我认为这种[@.disabled]方法很好,但是创建一些东西并通过不同的机制禁用它感觉很奇怪。幸运的是,还有一种更简单的方法。


首先,重要的是要记住完全:enter等同于. 事实上,它位于 Angular 源代码中。void => *

function parseAnimationAlias(alias: string, errors: string[]): string|TransitionMatcherFn {
  switch (alias) {
    case ':enter':
      return 'void => *';
    case ':leave':
      return '* => void';
    case ':increment':
      return (fromState: any, toState: any): boolean => parseFloat(toState) > parseFloat(fromState);
    case ':decrement':
      return (fromState: any, toState: any): boolean => parseFloat(toState) < parseFloat(fromState);
    default:
      errors.push(`The transition alias value "${alias}" is not supported`);
      return '* => *';
  }
}
Run Code Online (Sandbox Code Playgroud)

最简单的解决方案

同样重要的是要知道 Angular 的动画引擎仅匹配第一个触发器并运行它。

因此,您需要做的就是创建一个新的触发器并将其插入之前 :enter。该动画是无操作的。

transition('void => false', []),
transition(':enter', [...])
Run Code Online (Sandbox Code Playgroud)

而对于:leave

transition('false => void', []),
transition(':leave', [...])
Run Code Online (Sandbox Code Playgroud)

所以你的模板中的动画变成:

[@animation]="enableAnimations"
Run Code Online (Sandbox Code Playgroud)

当它匹配时false,它会匹配并且不执行任何操作。任何其他值都会匹配,:enter这当然是 true void => *

这样做的好处是它不会破坏任何已经使用的东西,[@animation]因为它仍然void => *像以前一样匹配。

注意:即使在无操作动画之后,任何(done)处理程序仍然会被执行 - 因此,如果您使用处理程序,请确保它在没有动画时执行正确的操作。