如何在 Angular 中有条件地为 :enter 和 :leave 转换设置动画?
How to animate :enter & :leave transitions conditionally in Angular?
我有一个列表,其中的项目有这样的动画:
<li @animation>
这是我的动画触发器:
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
])
])
如何有条件地为特定项目打开on/off此动画?实际上我正在寻找某事。像这样:
<li [@animation]=item.isAnimated>
根本不起作用。
不幸的是 Angular 文档中只有一句话:
For elements entering or leaving a page (inserted or removed from the
DOM), you can make the animations conditional. For example, use *ngIf
with the animation trigger in the HTML template.
但是当我将动画注释与 *ngIf 结合使用时,非动画项目显然根本不会显示:
<li *ngIf="item.isAnimated" @animation>
我想进一步显示所有项目,而不考虑 isAnimated 标志。我只想为特定项目打开 on/off 动画。
澄清一下: Angulars :enter 和 :leave 关键字用于动画组件,如果他们是进入或离开dom。听起来很简单,但这正是您的方法和您试图实现的目标的问题。不仅仅是动画,如果 dom 中有一个新元素,您希望它更加自定义,因此您需要自己的状态,可以在列表条目的 ngOnInit 和 ngOnDestroy 中由您自己控制。
方法可能如下:
@Component({
animations: [
trigger('animation', [
state('invisible', style({ height: '0px', 'padding-top': '0', 'padding-bottom': '0'}),
state('visible', style({ height: '*', 'padding-top': '*', 'padding-bottom': '*'})
transition('invisible => visible', animate('0.5s'))
transition('visible => invisible', animate('0.5s'))
])
],
})
private readonly isAnimated: boolean = false/true //Where ever you get this value.
public animationState: string //Or Enum with visible/invisible.
public ngOnInit(): void {
if (this.isAnimated) {
animationState = 'visible'
}
}
public ngOnDestroy(): void {
if (this.isAnimated && this.animationState === 'visible') {
animationState = 'invisible'
}
}
<li [@animation]="animationState"/>
如果此方法还有任何疑问或问题 - 让我知道,我们可以调整和讨论。
根据Angular IO:
当为真时,特殊动画控件绑定@.disabled 绑定会阻止所有动画呈现。将 @.disabled 绑定放在元素上以禁用元素本身的动画,以及元素内的任何内部动画触发器。
以下示例展示了如何使用此功能:
@Component({
selector: 'my-component',
template: `
<div [@.disabled]="isDisabled">
<div [@childAnimation]="exp"></div>
</div>
`,
animations: [
trigger("childAnimation", [
// ...
])
]
})
class MyComponent {
isDisabled = true;
exp = '...';
}
当@.disabled 为真时,它会阻止@childAnimation 触发器以及任何内部动画。
创建一个no-op动画触发器并插入到:enter
之前
我认为 [@.disabled]
方法很好,但创建一些东西并通过不同的机制禁用它感觉很奇怪。幸运的是,还有一种更简单的方法。
首先,请务必记住 :enter
完全 等同于 void => *
。事实上,它在 Angular 源代码中。
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 '* => *';
}
}
最简单的解决方案
了解 Angular 的动画引擎仅匹配 第一个 触发器并运行它也很重要。
因此,您需要做的就是创建一个新触发器并将其插入之前 :enter
。这个动画是no-op.
transition('void => false', []),
transition(':enter', [...])
而 :leave
transition('false => void', []),
transition(':leave', [...])
所以你在模板中的动画变成:
[@animation]="enableAnimations"
当它是 false
时,它将匹配并且不执行任何操作。任何其他值都会匹配 :enter
这当然是 void => *
.
这样做的好处是它不会破坏任何已经使用 [@animation]
的东西,因为它仍然像以前一样匹配 void => *
。
注意:即使在 no-op 动画之后,任何 (done)
处理程序仍会执行 - 所以如果您使用一个处理程序,请确保它在没有动画时执行正确的操作。
我有一个列表,其中的项目有这样的动画:
<li @animation>
这是我的动画触发器:
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
])
])
如何有条件地为特定项目打开on/off此动画?实际上我正在寻找某事。像这样:
<li [@animation]=item.isAnimated>
根本不起作用。
不幸的是 Angular 文档中只有一句话:
For elements entering or leaving a page (inserted or removed from the DOM), you can make the animations conditional. For example, use *ngIf with the animation trigger in the HTML template.
但是当我将动画注释与 *ngIf 结合使用时,非动画项目显然根本不会显示:
<li *ngIf="item.isAnimated" @animation>
我想进一步显示所有项目,而不考虑 isAnimated 标志。我只想为特定项目打开 on/off 动画。
澄清一下: Angulars :enter 和 :leave 关键字用于动画组件,如果他们是进入或离开dom。听起来很简单,但这正是您的方法和您试图实现的目标的问题。不仅仅是动画,如果 dom 中有一个新元素,您希望它更加自定义,因此您需要自己的状态,可以在列表条目的 ngOnInit 和 ngOnDestroy 中由您自己控制。
方法可能如下:
@Component({
animations: [
trigger('animation', [
state('invisible', style({ height: '0px', 'padding-top': '0', 'padding-bottom': '0'}),
state('visible', style({ height: '*', 'padding-top': '*', 'padding-bottom': '*'})
transition('invisible => visible', animate('0.5s'))
transition('visible => invisible', animate('0.5s'))
])
],
})
private readonly isAnimated: boolean = false/true //Where ever you get this value.
public animationState: string //Or Enum with visible/invisible.
public ngOnInit(): void {
if (this.isAnimated) {
animationState = 'visible'
}
}
public ngOnDestroy(): void {
if (this.isAnimated && this.animationState === 'visible') {
animationState = 'invisible'
}
}
<li [@animation]="animationState"/>
如果此方法还有任何疑问或问题 - 让我知道,我们可以调整和讨论。
根据Angular IO:
当为真时,特殊动画控件绑定@.disabled 绑定会阻止所有动画呈现。将 @.disabled 绑定放在元素上以禁用元素本身的动画,以及元素内的任何内部动画触发器。
以下示例展示了如何使用此功能:
@Component({
selector: 'my-component',
template: `
<div [@.disabled]="isDisabled">
<div [@childAnimation]="exp"></div>
</div>
`,
animations: [
trigger("childAnimation", [
// ...
])
]
})
class MyComponent {
isDisabled = true;
exp = '...';
}
当@.disabled 为真时,它会阻止@childAnimation 触发器以及任何内部动画。
创建一个no-op动画触发器并插入到:enter
之前
我认为 [@.disabled]
方法很好,但创建一些东西并通过不同的机制禁用它感觉很奇怪。幸运的是,还有一种更简单的方法。
首先,请务必记住 :enter
完全 等同于 void => *
。事实上,它在 Angular 源代码中。
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 '* => *';
}
}
最简单的解决方案
了解 Angular 的动画引擎仅匹配 第一个 触发器并运行它也很重要。
因此,您需要做的就是创建一个新触发器并将其插入之前 :enter
。这个动画是no-op.
transition('void => false', []),
transition(':enter', [...])
而 :leave
transition('false => void', []),
transition(':leave', [...])
所以你在模板中的动画变成:
[@animation]="enableAnimations"
当它是 false
时,它将匹配并且不执行任何操作。任何其他值都会匹配 :enter
这当然是 void => *
.
这样做的好处是它不会破坏任何已经使用 [@animation]
的东西,因为它仍然像以前一样匹配 void => *
。
注意:即使在 no-op 动画之后,任何 (done)
处理程序仍会执行 - 所以如果您使用一个处理程序,请确保它在没有动画时执行正确的操作。