Spec-Zone.ru › Angular 2

Анимации

Руководство по системе анимации Angular.

Движение является важным аспектом дизайна современных веб-приложений. Хорошие пользовательские интерфейсы плавно переходят между состояниями с привлекательными анимациями, которые обращают внимание там, где это необходимо. Хорошо спроектированные анимации могут сделать пользовательский интерфейс не только более интересным, но и более удобным в использовании.

Система анимации Angular позволяет создавать анимации, которые выполняются с той же производительностью, что и чистые CSS-анимации. Вы также можете тесно интегрировать логику анимации с остальной частью кода вашего приложения для удобства управления.

Анимации Angular основаны на стандартном API веб-анимаций и работают напрямую в браузерах, которые его поддерживают.

Для других браузеров требуется полифилл. Скачайте web-animations.min.js с GitHub и добавьте его на свою страницу.

Содержание

  • Пример: Переход между двумя состояниями.
  • Состояния и переходы.
  • Пример: Вход и выход.
  • Пример: Вход и выход из разных состояний.
  • Анимируемые свойства и единицы измерения.
  • Автоматическое вычисление свойств.
  • Настройка времени анимации.
  • Мультиэтапные анимации с ключевыми кадрами.
  • Параллельные группы анимаций.
  • Обратные вызовы анимации.

Примеры на этой странице доступны как живой пример.

Быстрый старт: Переход между двумя состояниями

A simple transition animation

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

Анимации определяются внутри @Component метаданных. Перед добавлением анимаций вам необходимо импортировать несколько функций, специфичных для анимаций:

hero-list-basic.component.ts

import {
  Component,
  Input,
  trigger,
  state,
  style,
  transition,
  animate
} from '@angular/core';

С помощью этих функций вы можете определить триггер анимации, названный heroState в метаданных компонента. Он использует анимации для перехода между двумя состояниями: active и inactive. Когда герой активен, элемент отображается несколько большего размера и более светлого цвета.

hero-list-basic.component.ts (@Component excerpt)

  animations: [
    trigger('heroState', [
      state('inactive', style({
        backgroundColor: '#eee',
        transform: 'scale(1)'
      })),
      state('active',   style({
        backgroundColor: '#cfd8dc',
        transform: 'scale(1.1)'
      })),
      transition('inactive => active', animate('100ms ease-in')),
      transition('active => inactive', animate('100ms ease-out'))
    ])
  ]

В этом примере вы определяете стили анимации (цвет и преобразование) прямо в метаданных анимации.

Теперь, используя синтаксис [@triggerName], прикрепите анимацию, которую вы только что определили, к одному или нескольким элементам в шаблоне компонента.

hero-list-basic.component.ts (excerpt)

template: `
  <ul>
    <li *ngFor="let hero of heroes"
        [@heroState]="hero.state"
        (click)="hero.toggleState()">
      {{hero.name}}
    </li>
  </ul>
`,

Здесь триггер анимации применяется ко всем элементам, повторяемым ngFor. Каждый из повторяющихся элементов анимируется независимо. Значение атрибута привязано к выражению hero.state и всегда равно либо active, либо inactive.

С этой настройкой появляется анимированный переход всякий раз, когда объект героя меняет состояние. Вот полная реализация компонента:

hero-list-basic.component.ts

import {
  Component,
  Input,
  trigger,
  state,
  style,
  transition,
  animate
} from '@angular/core';

import { Heroes } from './hero.service';

@Component({
  selector: 'hero-list-basic',
  template: `
    <ul>
      <li *ngFor="let hero of heroes"
          [@heroState]="hero.state"
          (click)="hero.toggleState()">
        {{hero.name}}
      </li>
    </ul>
  `,
  styleUrls: ['./hero-list.component.css'],
  animations: [
    trigger('heroState', [
      state('inactive', style({
        backgroundColor: '#eee',
        transform: 'scale(1)'
      })),
      state('active',   style({
        backgroundColor: '#cfd8dc',
        transform: 'scale(1.1)'
      })),
      transition('inactive => active', animate('100ms ease-in')),
      transition('active => inactive', animate('100ms ease-out'))
    ])
  ]
})
export class HeroListBasicComponent {
  @Input() heroes: Heroes;
}

Состояния и переходы

Анимации Angular определяются как логические состояния и переходы между состояниями.

Состояние анимации — это строковое значение, которое вы определяете в коде приложения. В примере выше состояния 'active' и 'inactive' основаны на логическом состоянии объектов героя. Источником состояния может быть простой атрибут объекта, как в этом случае, или значение, вычисленное в методе. Важно то, что вы можете прочитать его в шаблон компонента.

Вы можете определить стили для каждого состояния анимации:

state('inactive', style({
  backgroundColor: '#eee',
  transform: 'scale(1)'
})),
state('active',   style({
  backgroundColor: '#cfd8dc',
  transform: 'scale(1.1)'
})),

Эти state определения задают конечные стили каждого состояния. Они применяются к элементу после перехода в это состояние и остаются до тех пор, пока он находится в этом состоянии. По сути, вы определяете, какие стили имеет элемент в разных состояниях.

После определения состояний вы можете определить переходы между состояниями. Каждый переход управляет временем переключения между одним набором стилей и другим:

transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
In Angular animations you define states and transitions between states

Если несколько переходов имеют одинаковую конфигурацию времени, вы можете объединить их в одно transition определение:

transition('inactive => active, active => inactive',
 animate('100ms ease-out'))

Когда оба направления перехода имеют одинаковую настройку времени, как в предыдущем примере, вы можете использовать сокращенный синтаксис <=>:

transition('inactive <=> active', animate('100ms ease-out'))

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

transition('inactive => active', [
  style({
    backgroundColor: '#cfd8dc',
    transform: 'scale(1.3)'
  }),
  animate('80ms ease-in', style({
    backgroundColor: '#eee',
    transform: 'scale(1)'
  }))
]),

Состояние по умолчанию *

Состояние по умолчанию * («символ подстановки») соответствует любому состоянию анимации. Это полезно для определения стилей и переходов, которые применяются независимо от того, в каком состоянии находится анимация. Например:

  • Переход active => * применяется, когда состояние элемента меняется с active на любое другое.
  • Переход * => * применяется, когда происходит любое изменение между двумя состояниями.
The wildcard state can be used to match many different transitions at once

Состояние void

Специальное состояние, называемое void , может применяться к любой анимации. Оно применяется, когда элемент не прикреплён к представлению, возможно, потому что он ещё не добавлен или был удалён. Состояние void полезно для определения анимаций входа и выхода.

Например, переход * => void применяется, когда элемент покидает представление, независимо от того, в каком состоянии он находился перед уходом.

The void state can be used for enter and leave transitions

Состояние по умолчанию * также соответствует void.

Пример: Вход и выход

Enter and leave animations

Используя состояния void и * , вы можете определить переходы, которые анимируют вход и выход элементов:

  • Вход: void => *
  • Выход: * => void

Например, в массиве animations ниже есть два перехода, которые используют синтаксис void => * и * => void для анимации входа и выхода элемента в представление.

hero-list-enter-leave.component.ts (excerpt)

animations: [
  trigger('flyInOut', [
    state('in', style({transform: 'translateX(0)'})),
    transition('void => *', [
      style({transform: 'translateX(-100%)'}),
      animate(100)
    ]),
    transition('* => void', [
      animate(100, style({transform: 'translateX(100%)'}))
    ])
  ])
]

Обратите внимание, что в этом случае стили применяются к состоянию «пусто» непосредственно в определениях переходов, а не в отдельном определении state(void) . Таким образом, преобразования различны при входе и выходе: элемент входит слева и выходит справа.

Эти две распространённые анимации имеют свои псевдонимы:

transition(':enter', [ ... ]); // void => *
transition(':leave', [ ... ]); // * => void

Пример: Вход и выход из разных состояний

Enter and leave animations combined with state animations

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

  • Вход неактивного героя: void => inactive
  • Вход активного героя: void => active
  • Выход неактивного героя: inactive => void
  • Выход активного героя: active => void

Это даёт вам точный контроль над каждым переходом:

This example transitions between active, inactive, and void states

hero-list-enter-leave.component.ts (excerpt)

animations: [
  trigger('heroState', [
    state('inactive', style({transform: 'translateX(0) scale(1)'})),
    state('active',   style({transform: 'translateX(0) scale(1.1)'})),
    transition('inactive => active', animate('100ms ease-in')),
    transition('active => inactive', animate('100ms ease-out')),
    transition('void => inactive', [
      style({transform: 'translateX(-100%) scale(1)'}),
      animate(100)
    ]),
    transition('inactive => void', [
      animate(100, style({transform: 'translateX(100%) scale(1)'}))
    ]),
    transition('void => active', [
      style({transform: 'translateX(0) scale(0)'}),
      animate(200)
    ]),
    transition('active => void', [
      animate(200, style({transform: 'translateX(0) scale(0)'}))
    ])
  ])
]

Анимируемые свойства и единицы измерения

Поскольку поддержка анимации Angular основана на Web Animations, вы можете анимировать любое свойство, которое браузер считает анимируемым. Это включает позиции, размеры, преобразования, цвета, границы и многие другие. W3C поддерживает список анимируемых свойств на своей странице CSS Transitions.

Для числовых свойств позиции вы можете определить единицу, указав значение в виде строки с соответствующим суффиксом:

  • '50px'
  • '3em'
  • '100%'

Если вы не укажете единицу при указании размерности, Angular предполагает значение по умолчанию px:

  • 50 равносильно '50px'

Автоматическое вычисление свойств

Animation with automated height calculation

Иногда значение размерного свойства стиля известно только во время выполнения. Например, ширина и высота элементов часто зависят от их содержимого и размера экрана. Эти свойства часто сложно анимировать с помощью CSS.

В таких случаях вы можете использовать специальное значение свойства * , чтобы значение свойства вычислялось во время выполнения, а затем подставлялось в анимацию.

В этом примере анимация выхода берёт высоту элемента перед выходом и анимирует её от этой высоты до нуля:

animations: [
  trigger('shrinkOut', [
    state('in', style({height: '*'})),
    transition('* => void', [
      style({height: '*'}),
      animate(250, style({height: 0}))
    ])
  ])
]

Настройка времени анимации

Есть три свойства времени, которые вы можете настроить для каждого перехода анимации: длительность, задержка и функция сглаживания. Все они объединены в одну строку времени перехода.

Длительность

Длительность определяет, сколько времени занимает анимация от начала до конца. Вы можете определить длительность тремя способами:

  • Как простое число в миллисекундах: 100
  • В строке, как миллисекунды: '100ms'
  • В строке, как секунды: '0.1s'

Задержка

```

Задержка определяет время между триггером анимации и началом перехода. Вы можете задать её, добавив её в ту же строку после значения длительности. Она также поддерживает те же форматы, что и длительность:

  • Ожидание 100 мс, затем выполнение в течение 200 мс: '0.2s 100ms'

Функция плавного изменения

Функция плавного изменения управляет тем, как анимация ускоряется и замедляется во время своего выполнения. Например, функция ease-in заставляет анимацию начинаться относительно медленно, но набирать скорость по мере прогресса. Вы можете управлять функцией плавного изменения, добавив её в качестве третьего значения в строке после длительности и задержки (или в качестве второго значения, если задержки нет):

  • Ожидание 100 мс, затем выполнение в течение 200 мс, с функцией плавного изменения: '0.2s 100ms ease-out'
  • Выполнение в течение 200 мс, с функцией плавного изменения: '0.2s ease-in-out'
Animations with specific timings

Пример

Вот несколько примеров пользовательских временных характеристик в действии. И ввод, и вывод длятся по 200 миллисекунд, то есть 0.2s, но у них разные функции плавного изменения. Вывод начинается после небольшой задержки в 10 миллисекунд, как указано в '0.2s 10 ease-out':

hero-list-timings.component.ts (фрагмент)

animations: [
  trigger('flyInOut', [
    state('in', style({opacity: 1, transform: 'translateX(0)'})),
    transition('void => *', [
      style({
        opacity: 0,
        transform: 'translateX(-100%)'
      }),
      animate('0.2s ease-in')
    ]),
    transition('* => void', [
      animate('0.2s 10 ease-out', style({
        opacity: 0,
        transform: 'translateX(100%)'
      }))
    ])
  ])
]

Мультиэтапные анимации с ключевыми кадрами

Animations with some bounce implemented with keyframes

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

Для каждого ключевого кадра вы указываете смещение, которое определяет, в какой момент анимации применяется этот ключевой кадр. Смещение — это число от нуля (начало анимации) до единицы (конец).

В этом примере добавлены некоторые "отскоки" в анимации ввода и вывода с ключевыми кадрами:

hero-list-multistep.component.ts (фрагмент)

animations: [
  trigger('flyInOut', [
    state('in', style({transform: 'translateX(0)'})),
    transition('void => *', [
      animate(300, keyframes([
        style({opacity: 0, transform: 'translateX(-100%)', offset: 0}),
        style({opacity: 1, transform: 'translateX(15px)',  offset: 0.3}),
        style({opacity: 1, transform: 'translateX(0)',     offset: 1.0})
      ]))
    ]),
    transition('* => void', [
      animate(300, keyframes([
        style({opacity: 1, transform: 'translateX(0)',     offset: 0}),
        style({opacity: 1, transform: 'translateX(-15px)', offset: 0.7}),
        style({opacity: 0, transform: 'translateX(100%)',  offset: 1.0})
      ]))
    ])
  ])
]

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

Определение смещений для ключевых кадров необязательно. Если вы их опустите, смещения с равномерным распределением будут автоматически назначены. Например, три ключевых кадра без заданных смещений получают смещения 0, 0.5, и 1.

Параллельные группы анимаций

Parallel animations with different timings, implemented with groups

Вы уже видели, как анимировать несколько свойств стиля одновременно: просто поместите их в одно и то же определение style().

Но вы также можете настроить различные временные характеристики для анимаций, которые происходят параллельно. Например, вы можете анимировать два свойства CSS, но использовать разные функции плавного изменения для каждого из них.

Для этого можно использовать группы анимаций. В этом примере использование групп как для ввода, так и для вывода позволяет использовать две разные конфигурации временных характеристик. Обе применяются к одному и тому же элементу параллельно, но выполняются независимо друг от друга:

hero-list-groups.component.ts (фрагмент)

animations: [
  trigger('flyInOut', [
    state('in', style({width: 120, transform: 'translateX(0)', opacity: 1})),
    transition('void => *', [
      style({width: 10, transform: 'translateX(50px)', opacity: 0}),
      group([
        animate('0.3s 0.1s ease', style({
          transform: 'translateX(0)',
          width: 120
        })),
        animate('0.3s ease', style({
          opacity: 1
        }))
      ])
    ]),
    transition('* => void', [
      group([
        animate('0.3s ease', style({
          transform: 'translateX(50px)',
          width: 10
        })),
        animate('0.3s 0.2s ease', style({
          opacity: 0
        }))
      ])
    ])
  ])
]

Одна группа анимирует преобразование элемента и ширину; другая группа анимирует непрозрачность.

Обратные вызовы анимации

Обратный вызов срабатывает, когда анимация запускается и когда она завершается.

В примере с ключевыми кадрами у вас есть обратный вызов trigger с именем @flyInOut. Вы можете подключить эти обратные вызовы следующим образом:

hero-list-multistep.component.ts (фрагмент)

template: `
  <ul>
    <li *ngFor="let hero of heroes"
        (@flyInOut.start)="animationStarted($event)"
        (@flyInOut.done)="animationDone($event)"
        [@flyInOut]="'in'">
      {{hero.name}}
    </li>
  </ul>
`,

Обратные вызовы получают AnimationTransitionEvent, который содержит полезные свойства, такие как fromState, toState и totalTime.

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

© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://v2.angular.io/docs/ts/latest/guide/animations.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API