Angular 如何延迟/交错子组件内的动画

问题描述 投票:0回答:4

我有一个带有动画的子组件

child.component.ts

@Component({
  selector: 'child',
  animations:[
    // animations
   ]
})
export class ChildComponent { ... }

还有一个父组件,在 html 中有 2 个子组件

parent.component.hmtl.ts

...
<child></child>
<child></child>
...

Stackblitz 示例

我想要实现的是在父组件中错开子组件的动画。因此第二个子组件应该在 X 秒后开始动画。

animateChild() 听起来好像它可能有用,但我不知道如何使用它。这是正确的解决方案吗?如果是这样,一个例子将非常有帮助。

提前致谢

编辑:animateChild() 似乎不适用于这种情况。显然它只适用于父组件中定义的动画。

EDIT2:我认为可能有一种解决方法,可以通过在子组件内部的动画中添加延迟来解决。

child.component.ts

@Component({
  selector: 'child',
  animations:[
    animate(x),
    // animations
   ]
})
export class ChildComponent { ... }

x 将是一个变量,它会随着每个子组件而增加。 这个解决方法对我来说看起来有点混乱

EDIT3:到目前为止的答案或多或少是我在第二次编辑中提到的解决方案。虽然这些确实有效,但我仍然认为它们是解决方法。

我正在寻找一种仅涉及父组件的解决方案,因此子组件应保持与这个非工作示例

中的方式相同
angular angular-animations
4个回答
12
投票

根据动画函数中的角度文档。

第二个参数,延迟,与持续时间具有相同的语法。为了 示例:

等待100ms,然后运行200ms:'0.2s 100ms'

完整阅读这里

所以,我们的目标是传递第二个参数,如下所示

animate('2000ms {{delay}}ms'

首先,让我们向子组件添加输入参数,以便我们可以接受来自父组件的输入值:

export class ChildComponent implements OnInit {
  @Input() delay: number = 0;
  constructor() { }    
}

现在让父组件传递参数值

<p>child1</p>
<app-child [delay]="0"></app-child>

<p>child2</p>
<app-child [delay]="1000"></app-child>
<p>child2 should have a delay</p>

在您的子组件中,我们需要将此参数传递给动画触发器,因此它看起来像这样

<p [@childAnimation]="{value:'',params:{delay:delay}}">
    IIIIIIIIIIIIIIIIII
</p>

最后我们可以更改动画以支持此参数值

animations: [
    trigger('childAnimation', [
      transition(':enter', [
        animate('2000ms {{delay}}ms', style({ transform: 'translateX(80%)' })),
        animate('2000ms', style({ transform: 'translateX(0)' })),
      ], { params: { delay: 0 } })
    ])
  ]

现在一切都好,你现在应该延迟输入。

在这里查看演示


4
投票

这些不是唯一的选择,但它们是我所知道的。兼容 Angular 7。

工作 Stackblitz 演示

选项 1:主机绑定和状态

在子组件中,将动画状态声明为主机绑定。

@HostBinding('@animationState') animstate : string = 'preanimationstate';

然后在子组件中使用正常输入来获取延迟:

@Input('delay') delay : number;

像这样传递延迟:

<child-component [delay]="500"></child-component>

所以现在在 OnInit 中你可以使用超时:

let self = this;
window.setTimeout(function () {
    self.animstate = 'newstate';
}, self.delay);

推理:

看起来有生命的孩子也可以成为你的救星,但这种方式也非常直接和简单。希望有帮助。

选项 2:将动画移动到 HostComponent 并手动应用状态

您还可以将动画定义(如果使用状态和转换)从 child.component.ts 移动到 parent.component.ts,然后使用初始状态修饰符启动所有子组件,如下所示:

<child [@animstate]="initial"></child>>

然后通过 ViewChildren:

获取元素
@ViewChildren(ChildComponent) childComponents as QueryList<ChildComponent>;

这可以通过 AfterViewInit 访问。使用 for/each 循环和

window.setTimeout
函数在后视图初始化中应用您的状态。


2
投票

以防万一有人再次遇到这个问题:如果您希望两个动画同时播放,您只需使用

group
animateChild
即可。基本上,在第一篇文章中链接的 plunker 中,您必须将
outerTransition
替换为以下内容:

const outerTransition = transition('void => *', [
  style({opacity: 0}),
  group([
    animate(2000, style({opacity: 1})),
    query('@inner', [
      animateChild()
    ]),
  ]),
]);

0
投票

您实际上可以使用 stagger 方法和动画 query 来实现此目的:

演示

添加此:

import { Component } from '@angular/core';
import {
  trigger,
  style,
  animate,
  query,
  stagger,
  transition,
} from '@angular/animations';


const transition1 = trigger('listAnimation', [
  transition('* => *', [ // each time the binding value changes
    query(':leave', [
      stagger(-100, [
        animate('0.5s', style({ opacity: 0 }))
      ])
    ], { optional: true }),
    query(':enter', [
      style({ opacity: 0 }),
      stagger(500, [
        animate('0.5s', style({ opacity: 1 }))
      ])
    ], { optional: true })
  ])
])

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  animations: [
    transition1
  ]
})
export class AppComponent {

  items = [];

  showItems() {
    this.items = [0,1,2,3,4];
  }

  hideItems() {
    this.items = [];
  }

  toggle() {
    this.items.length ? this.hideItems() : this.showItems();
   }

}

您必须使用的唯一修改是循环出您的子组件,我本以为这就是您可能计划做的,无论如何?

如果不只是创建一个虚拟数组,其项目数量与您希望显示的子组件的数量相匹配。

注意 leave 值的负值。这实际上颠倒了项目消失的顺序。

此技术的关键是完全从父组件控制动画。

留下子组件来执行自己的动画。

© www.soinside.com 2019 - 2024. All rights reserved.