Анимация Angular 5 вводит (void => состояние) работает, но оставляет (состояние => void) не работает - PullRequest
0 голосов
/ 24 ноября 2018

Работа в Angular 5. Попытка создать браузер изображений карусельного типа с нуля.Пользователь может нажать / провести, чтобы просмотреть следующее или предыдущее изображение.

Анимации типа :enter работают отлично (показано в моем коде как "void => next" и "void => prev").Однако анимационные переходы "next => void" и "prev => void" не происходят.

Кажется, что каждый ответ в Интернете вращается вокруг дочерних компонентов, создавая стиль для элемента display: block и вызывая detectChanges() после изменениягосударство.Это не сценарий дочернего компонента, я уже назначил "display: block" css элементам, даже за счет того, что включил его в стиль анимации, и я обязательно добавил detectChanges() сразу после изменения состояния,Ничего из этого не сработало.

Я где-то читал комментарий, в котором DeteChanges () не справился с задачей: больше не оставлял анимации.Их обходной путь состоял в том, чтобы обернуть код, удаляющий элемент из DOM, в обратный вызов setTimeout (). Даже это не сработало .

Дошло до того, что я просто скопировал / вставил весь блок кода из https://github.com/born2net/Angular-kitchen-sink/blob/master/src/comps/app2/notes/AnimateCards.ts, только изменяя имена переменных.Но даже это не сработало!

Это заставляет меня терять волосы.Пожалуйста, помогите мне.

Компонент (угловой 5 в машинописном тексте)

import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
import { trigger, transition, style, animate, keyframes } from '@angular/animations';

type Orientation = ('prev' | 'next' | 'none');

@Component({
  selector: 'app-album-browser',
  templateUrl: './album-browser.component.html',
  styleUrls: ['./album-browser.component.scss'],
  animations: [
    trigger('animateCarousel',
    [
      transition('prev => void', // ------> leaving ------->
      [
        animate('500ms ease-in-out', keyframes([
          style({ opacity: 1.0, left: 0 }),
          style({ opacity: 0.0, left: 200 })
        ]))
      ]),
      transition('void => prev', // ----> entering ---->
      [
        animate('500ms ease-in-out', keyframes([
          style({ opacity: 0.0, left: -200, zIndex: 2 }),
          style({ opacity: 1.0, left: 0, zIndex: 2 })
        ]))
      ]),
      transition('next => void', // <------- leaving <-------
      [
        animate('500ms ease-in-out', keyframes([
          style({ opacity: 1.0, right: 0 }),
          style({ opacity: 0.0, right: 200 })
        ]))
      ]),
      transition('void => next', // <------- entering <--------
      [
        animate('500ms ease-in-out', keyframes([
          style({ opacity: 0.0, right: -200, zIndex: 2 }),
          style({ opacity: 1.0, right: 0, zIndex: 2 })
        ]))
      ])
    ])
  ]
})

export class AlbumBrowserComponent implements OnInit, AfterViewInit {

  private readonly SWIPE_ACTION = { LEFT: 'swipeleft', RIGHT: 'swiperight'};
  public readonly LEFT = 'LEFT';
  public readonly RIGHT = 'RIGHT';

  public orientation: Orientation = 'none';

  public images: string[] = [];
  public selectedImage: string[] = [];
  public changeDetectorRef: ChangeDetectorRef;

  constructor(changeDetectorRef: ChangeDetectorRef) {
    this.changeDetectorRef = changeDetectorRef;
    this.images.push('../../../assets/images/1.jpg');
    this.images.push('../../../assets/images/2.jpg');
    this.images.push('../../../assets/images/3.jpg');
    this.selectedImage.push(this.images[0]);
  }

  ngOnInit() {
  }

  public click(direction: string) {
    if (direction === this.LEFT) {
      this.swipe(this.SWIPE_ACTION.LEFT);
    }

    if (direction === this.RIGHT) {
      this.swipe(this.SWIPE_ACTION.RIGHT);
    }
  }

  public swipe(action = this.SWIPE_ACTION.RIGHT) {

    let res: string;
    const index = this.images.indexOf(this.selectedImage[0]);

    if (action === this.SWIPE_ACTION.LEFT) {
      this.orientation = 'next';
      this.selectedImage = [];
      this.changeDetectorRef.detectChanges();

      res = !!this.images[index + 1] ?
        this.images[index + 1] :
        this.images[0];
    }

    if (action === this.SWIPE_ACTION.RIGHT) {
      this.orientation = 'prev';
      this.selectedImage = [];
      this.changeDetectorRef.detectChanges();

      res = !!this.images[index - 1] ?
        this.images[index - 1] :
        this.images[this.images.length - 1];
    }

    this.selectedImage.push(res);
  }

}

Шаблон

<div class="album-browser-container">
  <div class="left arrow small-glow" (click)="click(LEFT)"></div>
  <div class="viewport-frame glow">
    <div class="viewport">
      <div class="image-slider" 
        (swipeleft)="swipe($event.type)"
        (swiperight)="swipe($event.type)">
        <div class="carousel"
          *ngFor="let image of selectedImage">
          <div class="image-container"
            [@animateCarousel]="orientation">
            <img [src]="image" class="album-image">
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="right arrow small-glow" (click)="click(RIGHT)"></div>
</div>

1 Ответ

0 голосов
/ 24 ноября 2018

TLDR;используйте * ngIf вместо * ngFor и оберните обновление selectedImage в обратный вызов setTimeout.

Я натолкнулся на решение при отладке альтернативы, которую я придумал.Во время отладки я увидел, что анимация выхода работает, когда я ставлю точку останова в строке сброса массива.Запись GitHub, которую я разместил выше (https://github.com/born2net/Angular-kitchen-sink/blob/master/src/comps/app2/notes/AnimateCards.ts), дала мне большую часть пути, кажется, что более поздние версии Angular создали необходимость обрабатывать анимацию немного по-другому.

Вместо использованиядиректива *ngFor в div "image-container", я использую ngIf, привязанный к члену класса с именем "showIt" в компоненте. Сначала я обновляю Ориентацию и detectChanges (). Затем обновляем "showIt"«FALSE, за которым следует другой вызов detectChanges (). Это может показаться излишним, но когда я пропускаю инкрементные вызовы detectChanges (), почти кажется, что в« очереди »остались изменения DOM (из-за отсутствия лучшего термина), которые в конечном итоге выполняются при последующих вызовах Detechanges (). Затем я сохраняю целевой индекс для массива изображений в локальной переменной и, наконец, оборачиваю последующие вызовы, чтобы обновить selectedImage в обратном вызове setTimeout с тайм-аутом, установленным на то же самоевремя как анимация перехода.

Если вы думаете "тьфу, как ИнелеганЯ не могу согласиться с тем, что мне нужно было обернуть код в обратный вызов setTimeout.Но, похоже, это единственный способ обеспечить анимацию :enter и :leave.Основная причина моей первоначальной проблемы заключалась в том, что когда массив selectedImage был установлен пустым, DOM обновлялся так быстро, что анимация переопределялась до того, как анимация ухода даже могла быть обнаружена человеческим глазом.

Окончательный шаблон

<div class="album-browser-container">
  <div class="left arrow small-glow" (click)="click(LEFT)"></div>
  <div class="viewport-frame glow">
    <div class="viewport">
      <div class="image-slider" 
        (swipeleft)="swipe($event.type)"
        (swiperight)="swipe($event.type)">
        <div class="carousel">
          <div class="image-container"
            *ngIf="showIt"
            [@animateCarousel]="orientation">
            <img [src]="selectedImage[0]" 
              class="album-image"
              (swipeleft)="swipe($event.type)"
              (swiperight)="swipe($event.type)">
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="right arrow small-glow" (click)="click(RIGHT)"></div>
</div>

Анимации из моего ОП были действительно точными.Изменен только метод щелчка / удара.

Компонент (усеченный)

public swipe(action = this.SWIPE_ACTION.RIGHT) {

    let res: string;

    if (action === this.SWIPE_ACTION.LEFT) {
      this.orientation = 'next';
      this.changeDetectorRef.detectChanges();
      this.showIt = false;
      this.changeDetectorRef.detectChanges();

      const index = this.images.indexOf(this.selectedImage[0]);

      res = !!this.images[index + 1] ?
        this.images[index + 1] :
        this.images[0];

      setTimeout(() => {
        this.selectedImage = [];
        this.selectedImage.push(res);
        this.showIt = true;
        this.changeDetectorRef.detectChanges();
      }, 300);

    }

    if (action === this.SWIPE_ACTION.RIGHT) {
      this.orientation = 'prev';
      this.changeDetectorRef.detectChanges();
      this.showIt = false;
      this.changeDetectorRef.detectChanges();

      const index = this.images.indexOf(this.selectedImage[0]);

      res = !!this.images[index - 1] ?
        this.images[index - 1] :
        this.images[this.images.length - 1];

      setTimeout(() => {
        this.selectedImage = [];
        this.selectedImage.push(res);
        this.showIt = true;
        this.changeDetectorRef.detectChanges();
      }, 300);
    }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...