Угловая, как отложить/разбить анимацию внутри дочерних компонентов

У меня есть дочерний компонент с анимацией

child.component.ts

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

И родительский компонент, который имеет 2 дочерних компонента в HTML

parent.component.hmtl.ts

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

Пример Stackblitz

Чего я хочу добиться, так это ошеломить анимацию дочерних компонентов в родительском компоненте. Поэтому второй дочерний компонент должен запустить анимацию через X секунд.

Похоже, что animateChild() может работать, но я не могу понять, как его использовать. Это правильное решение? Если так, то пример был бы действительно полезен.

заранее спасибо

РЕДАКТИРОВАТЬ: animateChild(), кажется, не работает для этого случая. Очевидно, он работает только с анимациями, которые определены в родительском компоненте.

РЕДАКТИРОВАТЬ 2: Я думаю, что может быть обходной путь, добавив задержку для анимации внутри дочерних компонентов.

child.component.ts

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

X будет переменной, которая будет увеличиваться для каждого дочернего компонента. Этот обходной путь выглядит мне немного грязно

РЕДАКТИРОВАТЬ 3: ответы до сих пор являются более или менее решением, которое я упомянул во втором моем редактировании. Хотя они работают, я все равно считаю их обходными путями.

Я ищу решение, которое включает только родительский компонент, поэтому дочерний компонент должен оставаться таким же, как в этом нерабочем примере

Ответ 1

По угловой документации в анимационной функции.

Второй аргумент, задержка, имеет тот же синтаксис, что и длительность. Например:

Подождите 100 мс, а затем запустите 200 мс: "0,2 с 100 мс"

Полное чтение здесь

Итак, наша цель - передать второй параметр примерно так

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 } })
    ])
  ]

теперь все хорошо, теперь вы должны откладывать на входы.

Просмотрите демо здесь

Ответ 2

Это не единственные варианты, но я знаю их. Угловой 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. Примените свои состояния в init после представления с помощью цикла for/each и функции window.setTimeout.

Ответ 3

Аутсорсинг - эти ресурсы могут вам помочь.

1.) Существует демо -версия Stackblitz от ZouYouShun, которая показывает, как использовать animateChild().

2.) Анимация Stagger от Coursetro с использованием запроса перехода

3.) Sub Анимация с animateChild из yearmmoo

Ответ 4

На всякий случай, когда кто-то снова наткнется на эту проблему: если вы хотите, чтобы обе анимации играли одновременно, вам просто нужно использовать group и animateChild. В принципе, в плункере, связанном в первом посте, вы должны заменить outerTransition следующим:

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