在交叉淡入淡出动画中平滑地动画化容器的高度
Smoothly animating container's height in crossfade animation
我在 Angular 动画中无法获得所需的效果。一个典型的交叉淡入淡出,不透明度很好地交叉淡入淡出,但高度没有动画。
我做错了什么?
animations: [
trigger('fadeInOut', [
transition('* => *', [
style({ height: '*' }),
group([
query(':leave',
[
style({ opacity: 1, position: 'absolute', height: '*' }),
animate('1s', style({ opacity: 0, height: '*' })),
],
{ optional: true },
),
query(':enter',
[
style({ opacity: 0 }),
animate('1s', style({ opacity: 1, height: '*' })),
],
{ optional: true },
),
]),
]),
]),
],
恕我直言,这是一个相当复杂的动画,我使用了很多我通常不会使用的技巧,它们可能是一个更简单的解决方案。
我认为项目的高度是动态的,这是最大的挑战,但它使动画非常灵活。
由于我们有动态值,我们将使用 Angular 的 AnimationBuilder。
使用 AnimationBuilder 时,我们无法访问 :enter
和 :leave
查询,因此这两个元素都需要不断呈现。
让我们从简单的部分开始,CSS,它变得更简单了:
#holder {
position: relative;
overflow: hidden;
}
#show {
background-color: darkcyan;
}
#edit {
background-color: cornflowerblue;
visibility: hidden; <-- we start with the 'edit' panel hidden
position: absolute; <-- we start with the 'edit' panel hidden
}
模板:
<div #refHolder id="holder">
<div #refShow id="show">
<div>show</div>
<div>show</div>
<div>show</div>
</div>
<div #refEdit id="edit">
<div>edit</div>
<div>edit</div>
<div>edit</div>
<div>edit</div>
<div>edit</div>
<div>edit</div>
</div>
</div>
<button (click)="toggleState()">Toggle</button>
在这里,请注意对 3 个元素引用(#refHolder、#refShow、#refEdit)的引用,我们将在构建动画时使用它们来访问它们的属性。
另请注意 ID,它们都用于样式设置和动画期间的查询。
TS:
我们需要定义一组属性
state = true;
@ViewChild('refHolder') refHolder: ElementRef;
@ViewChild('refShow') refShow: ElementRef;
@ViewChild('refEdit') refEdit: ElementRef;
private animationFactory: AnimationFactory;
在构造函数中注入AnimationBuilder服务:
constructor(
private animationBuilder: AnimationBuilder,
) { }
让我们编写切换函数的代码,它将首先翻转状态,然后构建和播放动画。
toggleState() {
this.state = !this.state;
this.buildAndPlayAnimation();
}
现在,让我们来做最难的部分,构建动画:
private buildAndPlayAnimation() {
let animationFactory: AnimationFactory;
animationFactory = this.animationBuilder.build([
group([
query(this.state ? '#edit' : '#show', [
style({
position: 'absolute',
opacity: 1,
top: 0,
right: 0,
left: 0,
height: Math.max(this.state ? this.refShow.nativeElement.clientHeight : this.refEdit.nativeElement.clientHeight, this.refHolder.nativeElement.clientHeight),
}),
animate('.5s', style({
opacity: 0,
visibility: 'hidden',
})),
style({
top: 'auto',
bottom: 'auto',
right: 'auto',
height: '*',
})
]),
query(this.state ? '#show' : '#edit', [
style({
position: 'static',
opacity: 0,
height: this.refHolder.nativeElement.clientHeight,
visibility: 'visible',
}),
animate('.5s', style({
opacity: 1,
height: '*',
})),
])
])
]);
animationFactory.create(this.refHolder.nativeElement).play();
}
基本上,我使用三元运算符是为了不必两次创建动画,因为它需要以两种方式工作。项目设置为不可见且位置绝对,以不阻止用户与可见面板交互。
我在 Angular 动画中无法获得所需的效果。一个典型的交叉淡入淡出,不透明度很好地交叉淡入淡出,但高度没有动画。
我做错了什么?
animations: [
trigger('fadeInOut', [
transition('* => *', [
style({ height: '*' }),
group([
query(':leave',
[
style({ opacity: 1, position: 'absolute', height: '*' }),
animate('1s', style({ opacity: 0, height: '*' })),
],
{ optional: true },
),
query(':enter',
[
style({ opacity: 0 }),
animate('1s', style({ opacity: 1, height: '*' })),
],
{ optional: true },
),
]),
]),
]),
],
恕我直言,这是一个相当复杂的动画,我使用了很多我通常不会使用的技巧,它们可能是一个更简单的解决方案。
我认为项目的高度是动态的,这是最大的挑战,但它使动画非常灵活。
由于我们有动态值,我们将使用 Angular 的 AnimationBuilder。
使用 AnimationBuilder 时,我们无法访问 :enter
和 :leave
查询,因此这两个元素都需要不断呈现。
让我们从简单的部分开始,CSS,它变得更简单了:
#holder {
position: relative;
overflow: hidden;
}
#show {
background-color: darkcyan;
}
#edit {
background-color: cornflowerblue;
visibility: hidden; <-- we start with the 'edit' panel hidden
position: absolute; <-- we start with the 'edit' panel hidden
}
模板:
<div #refHolder id="holder">
<div #refShow id="show">
<div>show</div>
<div>show</div>
<div>show</div>
</div>
<div #refEdit id="edit">
<div>edit</div>
<div>edit</div>
<div>edit</div>
<div>edit</div>
<div>edit</div>
<div>edit</div>
</div>
</div>
<button (click)="toggleState()">Toggle</button>
在这里,请注意对 3 个元素引用(#refHolder、#refShow、#refEdit)的引用,我们将在构建动画时使用它们来访问它们的属性。
另请注意 ID,它们都用于样式设置和动画期间的查询。
TS:
我们需要定义一组属性
state = true;
@ViewChild('refHolder') refHolder: ElementRef;
@ViewChild('refShow') refShow: ElementRef;
@ViewChild('refEdit') refEdit: ElementRef;
private animationFactory: AnimationFactory;
在构造函数中注入AnimationBuilder服务:
constructor(
private animationBuilder: AnimationBuilder,
) { }
让我们编写切换函数的代码,它将首先翻转状态,然后构建和播放动画。
toggleState() {
this.state = !this.state;
this.buildAndPlayAnimation();
}
现在,让我们来做最难的部分,构建动画:
private buildAndPlayAnimation() {
let animationFactory: AnimationFactory;
animationFactory = this.animationBuilder.build([
group([
query(this.state ? '#edit' : '#show', [
style({
position: 'absolute',
opacity: 1,
top: 0,
right: 0,
left: 0,
height: Math.max(this.state ? this.refShow.nativeElement.clientHeight : this.refEdit.nativeElement.clientHeight, this.refHolder.nativeElement.clientHeight),
}),
animate('.5s', style({
opacity: 0,
visibility: 'hidden',
})),
style({
top: 'auto',
bottom: 'auto',
right: 'auto',
height: '*',
})
]),
query(this.state ? '#show' : '#edit', [
style({
position: 'static',
opacity: 0,
height: this.refHolder.nativeElement.clientHeight,
visibility: 'visible',
}),
animate('.5s', style({
opacity: 1,
height: '*',
})),
])
])
]);
animationFactory.create(this.refHolder.nativeElement).play();
}
基本上,我使用三元运算符是为了不必两次创建动画,因为它需要以两种方式工作。项目设置为不可见且位置绝对,以不阻止用户与可见面板交互。