Как создать расширенную анимацию горизонтального списка в Angular

#javascript #angular #ionic-framework #animation #gsap

#javascript #angular #ionic-framework #Анимация #gsap

Вопрос:

Я ищу некоторую помощь с расширенной анимацией, которую я хочу создать. Есть gif, который (надеюсь) прояснит, чего я хочу, если это не ясно из следующего абзаца.

Подумайте об интерфейсе строк с каждыми 5 элементами. В приложении пользователь имеет возможность удалить элемент, щелкнув по нему. Когда пользователь делает это, каждый элемент после выбранного элемента должен перемещаться на место влево. Если элемент уже находится в самом левом месте, элемент должен поместиться в строку выше. Всякий раз, когда элемент перемещает строки, пользователь будет видеть, как элемент перемещается влево за пределы экрана, но в то же время перемещается на экран в строке над строкой, которую он оставил.

GIF, объясняющий это визуально: (пользователь нажимает на «8», чтобы скрыть его, а пользователь нажимает на «1», чтобы скрыть его, что означает, что элементы после выбранных элементов должны анимироваться в другом месте)

введите описание изображения здесь

Массив, который будет использоваться, уже довольно обширный, поэтому я не хочу сильно менять этот массив. Сначала я думал об изменении этого массива в массив массивов, где вы можете видеть первые массивы в виде строки. Разметка будет выглядеть следующим образом:

 <section *ngFor="let blockRow of orderedBlocks" class="block-row">
  <article [attr.data-id]="block.id"  *ngFor="let block of blockRow" class="block" [style.backgroundColor]="block.bgColor">
    <p [innerHTML]="'ID = '   block.id"></p>
    <ion-button (click)="completeBlock(block.id)">complete block</ion-button>
  </article>
</section>
 

Что создало бы следующий макет: макет разметки

Добавление анимации с:

 animations: [
trigger('items', [
  transition(':enter', [
    style({ transform: 'translateX(-100%)' }),
    animate('.5s ease-in-out',
      style({ transform: 'translateX(0) }))
  ]),
  transition(':leave', [
    style({ transform: 'translateX(0)'}),
    animate('.5s ease-in-out',
      style({ transform: 'translateX(-100%)' }))
  ])
])
 

Сделал бы так, чтобы все менялось так при каждом изменении, а не отдельных элементов.

Однако, как я уже сказал, мне это не нравится. Всякий раз, когда что-то меняется в элементе (что возможно в реальном приложении), каждый отдельный элемент будет повторно отображаться, поскольку нам нужно снова преобразовать его в этот специальный массив. Нет, не похоже, что с точки зрения производительности делать это при каждом изменении.

Хорошо, может быть, оператор modulo сработает, поэтому нам не нужно изменять исходный массив? Я также не смог понять это.

Я могу использовать анимацию Angular или даже gsap, но мне бы понравилось, если бы это было возможно без каких-либо изменений в массиве. Возможно ли это, и если да, то как?

Комментарии:

1. Одна из идей — добавить функцию trackBy в *ngFor . Таким образом, только если отслеживаемое свойство изменится, тогда привязка изменится, и анимация сработает. Вы пробовали это?

2. @BenBradshaw Это было бы необходимо для обоих циклов *ngFor? Я знаю, что trackBy хорош тем, что он выполняет действия только с измененным элементом вместо полного повторного рендеринга, но я не уверен, что это решение для этого. Действительно ли использование анимации сверху и trackBy приведет к анимации из gif? Как можно было бы разобраться со структурой данных? Должен ли это быть массив массивов или это может быть один большой массив, где шаблон разделит его на строки? Извините за все вопросы, хотя мне нравится анимация, мне довольно сложно понять, как ее реализовать.

3. Да, на обоих. Теперь я лучше понимаю, что ты имеешь в виду. Я подозреваю, что хорошим способом сделать это было бы изменить массив и позволить анимации реагировать на изменения массива. Что касается точной анимации с использованием API анимации, это займет некоторое время и займет некоторое время. У вас может быть более простая реализация с использованием анимации CSS3, хотя анимация angular дает вам дополнительное преимущество запроса :leave .

Ответ №1:

При нажатии на элемент вам нужно будет либо

  1. Абсолютно расположите все ваши элементы или
  2. Оберните все элементы подряд в контейнер, который будет анимирован.

Затем вам нужно будет продублировать все элементы, которые будут перенесены в другую строку (либо в контейнер предыдущей строки, либо полностью расположить его там, где он должен быть).

Затем вам нужно анимировать каждый из контейнеров (или абсолютно позиционированных элементов), которые вы хотите анимировать слева, на один прямоугольник (и интервал вокруг него).

Также было бы намного проще, если бы вы отключили возможность нажимать на второе поле, пока предыдущая анимация все еще продолжается.