Перейти к содержанию

Введение в анимацию Angular

📅 28.02.2022

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

Анимация может улучшить работу приложения и пользовательский опыт несколькими способами:

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

Как правило, анимация включает в себя несколько стилевых преобразований во времени. Элемент HTML может перемещаться, менять цвет, увеличиваться или уменьшаться, исчезать или соскальзывать со страницы.

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

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

W3C поддерживает список анимируемых свойств на своей странице CSS Transitions.

Об этом руководстве

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

Функции, описанные в этом руководстве — и более продвинутые функции, описанные в соответствующих руководствах по анимации Angular — демонстрируются в примере приложения.

Предварительные условия

Руководство предполагает, что вы знакомы с созданием базовых приложений Angular, как описано в следующих разделах:

Начало работы

Основными модулями Angular для анимации являются @angular/animations и @angular/platform-browser. Когда вы создаете новый проект с помощью CLI, эти зависимости автоматически добавляются в ваш проект.

Чтобы начать добавлять анимации Angular в свой проект, импортируйте модули, специфичные для анимации, вместе со стандартной функциональностью Angular.

Шаг 1: Включение модуля анимации

Импортируйте BrowserAnimationsModule, который внедряет возможности анимации в ваш корневой модуль приложения Angular.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
    imports: [BrowserModule, BrowserAnimationsModule],
    declarations: [],
    bootstrap: [],
})
export class AppModule {}

Когда вы используете CLI для создания приложения, корневой модуль приложения app.module.ts помещается в папку src/app.

Шаг 2: Импорт функций анимации в файлы компонентов

Если вы планируете использовать определенные функции анимации в файлах компонентов, импортируйте эти функции из @angular/animations.

1
2
3
4
5
6
7
8
9
import { Component, HostBinding } from '@angular/core';
import {
    trigger,
    state,
    style,
    animate,
    transition,
    // ...
} from '@angular/animations';

Смотрите сводку доступных функций анимации в конце этого руководства.

Шаг 3: Добавление свойства метаданных анимации

В файле компонента добавьте свойство метаданных animations: в декораторе @Component(). В свойство метаданных animations помещается триггер, определяющий анимацию.

1
2
3
4
5
6
7
8
@Component({
    selector: 'app-root',
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css'],
    animations: [
        // animation triggers go here
    ]
})

Анимация перехода

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

Когда кнопка находится в состоянии открыто, она видна и имеет желтый цвет.

Когда она находится в состоянии закрыта, она прозрачная и синяя.

В HTML эти атрибуты задаются с помощью обычных стилей CSS, таких как цвет и непрозрачность. В Angular используйте функцию style(), чтобы задать набор CSS-стилей для использования в анимации.

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

Давайте создадим новый компонент open-close для анимации с простыми переходами.

Выполните следующую команду в терминале, чтобы создать компонент:

1
ng g component open-close

Это создаст компонент в src/app/open-close.component.ts.

Состояние и стили анимации

Используйте функцию Angular state(), чтобы определить различные состояния для вызова в конце каждого перехода. Эта функция принимает два аргумента:

Уникальное имя, например open или close, и функцию style().

Используйте функцию style() для определения набора стилей, которые будут ассоциироваться с данным именем состояния. Вы должны использовать camelCase для атрибутов стиля, которые содержат тире, например backgroundColor, или обернуть их в кавычки, например 'background-color'.

Давайте посмотрим, как функция Angular state() работает с функцией style() для установки стилевых атрибутов CSS. В этом фрагменте кода для состояния одновременно устанавливается несколько атрибутов стиля.

В состоянии open кнопка имеет высоту 200 пикселей, непрозрачность 1 и желтый цвет фона.

1
2
3
4
5
6
// ...
state('open', style({
  height: '200px',
  opacity: 1,
  backgroundColor: 'yellow'
})),

В следующем состоянии closed кнопка имеет высоту 100 пикселей, непрозрачность 0.8 и цвет фона синий.

1
2
3
4
5
state('closed', style({
  height: '100px',
  opacity: 0.8,
  backgroundColor: 'blue'
})),

Переходы и синхронизация

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

Чтобы сделать изменение менее резким, необходимо определить анимацию transition, чтобы указать изменения, которые происходят между одним состоянием и другим в течение определенного периода времени. Функция transition() принимает два аргумента:

Первый аргумент принимает выражение, определяющее направление между двумя состояниями перехода, а второй аргумент принимает один или серию шагов animate().

Используйте функцию animate() для определения длины, задержки и смягчения перехода, а также для назначения функции style для определения стилей при переходе. Используйте функцию animate() для определения функции keyframes() для многошаговой анимации.

Эти определения помещаются во второй аргумент функции animate().

Метаданные анимации: duration, delay и easing

Функция animate() (второй аргумент функции перехода) принимает входные параметры timings и styles.

Параметр timings принимает либо число, либо строку, состоящую из трех частей.

1
animate (duration)

или

1
animate ('duration delay easing')

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

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

Второй аргумент, delay, имеет тот же синтаксис, что и duration. Например:

  • Подождать 100 мс, а затем выполнить 200 мс: 0.2s 100ms.

Третий аргумент, easing, управляет тем, как анимация ускоряется и замедляется во время выполнения. Например, ease-in заставляет анимацию начинаться медленно и набирать скорость по мере выполнения.

  • Подождите 100 мс, запустите 200 мс.

    Используйте кривую замедления, чтобы начать быстро и медленно замедляться до точки покоя:

    '0.2s 100ms ease-out'

  • Запуск в течение 200 мс без задержки.

    Используйте стандартную кривую, чтобы начать медленно, ускориться в середине, а затем медленно замедлиться в конце:

    '0.2s ease-in-out'

  • Запуск сразу, выполнение в течение 200 мс.

    Используйте кривую ускорения, чтобы начать медленно и закончить на полной скорости:

    '0.2s ease-in'

Общую информацию о кривых смягчения см. в теме Естественные кривые смягчения на сайте Material Design.

Этот пример обеспечивает переход из состояния open в closed с переходом между состояниями в течение 1 секунды.

1
2
3
transition('open => closed', [
  animate('1s')
]),

В предыдущем фрагменте кода оператор => обозначает однонаправленные переходы, а <=> — двунаправленные. Внутри перехода оператор animate() указывает, как долго длится переход.

В данном случае переход из состояния open в closed занимает 1 секунду, выраженную здесь как 1s.

Этот пример добавляет переход состояния из состояния closed в состояние open с дугой анимации перехода 0,5 секунды.

1
2
3
transition('closed => open', [
  animate('0.5s')
]),

Некоторые дополнительные замечания по использованию стилей в функциях state и transition.

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

  • Используйте transition() для определения промежуточных стилей, которые создают иллюзию движения во время анимации.

  • Когда анимация отключена, стили transition() можно пропустить, а стили state() — нет.

  • Включите несколько пар состояний в один и тот же аргумент transition():

    1
    transition( 'on => off, off => void' )
    

Запуск анимации

Анимация требует триггера, чтобы она знала, когда начинать. Функция trigger() собирает состояния и переходы и дает анимации имя, чтобы вы могли прикрепить его к запускающему элементу в шаблоне HTML.

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

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

В этом примере мы назовем триггер openClose и прикрепим его к элементу button. Триггер описывает открытое и закрытое состояния, а также тайминги для этих двух переходов.

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

Определение анимаций и прикрепление их к шаблону HTML

Анимации определяются в метаданных компонента, который управляет анимируемым элементом HTML. Поместите код, определяющий анимацию, в свойство animations: в декораторе @Component().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Component({
    selector: 'app-open-close',
    animations: [
        trigger('openClose', [
            // ...
            state(
                'open',
                style({
                    height: '200px',
                    opacity: 1,
                    backgroundColor: 'yellow',
                })
            ),
            state(
                'closed',
                style({
                    height: '100px',
                    opacity: 0.8,
                    backgroundColor: 'blue',
                })
            ),
            transition('open => closed', [animate('1s')]),
            transition('closed => open', [animate('0.5s')]),
        ]),
    ],
    templateUrl: 'open-close.component.html',
    styleUrls: ['open-close.component.css'],
})
export class OpenCloseComponent {
    isOpen = true;

    toggle() {
        this.isOpen = !this.isOpen;
    }
}

Когда вы определили триггер анимации для компонента, прикрепите его к элементу шаблона этого компонента, заключив имя триггера в скобки и предваряя его символом @. Затем вы можете привязать триггер к выражению шаблона, используя стандартный синтаксис привязки свойств Angular, как показано ниже, где triggerName — это имя триггера, а expression оценивает определенное состояние анимации.

1
<div [@triggerName]="expression">…</div>;

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

Следующий фрагмент кода связывает триггер со значением свойства isOpen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<nav>
    <button type="button" (click)="toggle()">
        Toggle Open/Close
    </button>
</nav>

<div
    [@openClose]="isOpen ? 'open' : 'closed'"
    class="open-close-container"
>
    <p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
</div>

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

Для элементов, входящих или выходящих со страницы (вставляемых или удаляемых из DOM), вы можете сделать анимацию условной. Например, используйте *ngIf с триггером анимации в шаблоне HTML.

В файле компонента задайте триггер, определяющий анимацию, как значение свойства animations: в декораторе @Component().

В файле шаблона HTML используйте имя триггера, чтобы прикрепить определенные анимации к анимируемому элементу HTML.

Обзор кода

Вот файлы кода, рассмотренные в примере перехода.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Component({
    selector: 'app-open-close',
    animations: [
        trigger('openClose', [
            // ...
            state(
                'open',
                style({
                    height: '200px',
                    opacity: 1,
                    backgroundColor: 'yellow',
                })
            ),
            state(
                'closed',
                style({
                    height: '100px',
                    opacity: 0.8,
                    backgroundColor: 'blue',
                })
            ),
            transition('open => closed', [animate('1s')]),
            transition('closed => open', [animate('0.5s')]),
        ]),
    ],
    templateUrl: 'open-close.component.html',
    styleUrls: ['open-close.component.css'],
})
export class OpenCloseComponent {
    isOpen = true;

    toggle() {
        this.isOpen = !this.isOpen;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<nav>
    <button type="button" (click)="toggle()">
        Toggle Open/Close
    </button>
</nav>

<div
    [@openClose]="isOpen ? 'open' : 'closed'"
    class="open-close-container"
>
    <p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
:host {
    display: block;
    margin-top: 1rem;
}

.open-close-container {
    border: 1px solid #dddddd;
    margin-top: 1em;
    padding: 20px 20px 0px 20px;
    color: #000000;
    font-weight: bold;
    font-size: 20px;
}

Резюме

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

Узнайте о более продвинутых возможностях анимации в Angular в разделе Анимация, начиная с продвинутых техник в transition and triggers.

Краткое описание API анимации

Функциональный API, предоставляемый модулем @angular/animations, обеспечивает специфический язык (DSL) для создания и управления анимацией в приложениях Angular. Полный список и синтаксические подробности основных функций и связанных с ними структур данных см. в API reference.

Название функции Что она делает
trigger() Запускает анимацию и служит контейнером для всех остальных вызовов функций анимации. HTML-шаблон привязывается к triggerName. Используйте первый аргумент для объявления уникального имени триггера. Используется синтаксис массива.
style() Определяет один или несколько стилей CSS для использования в анимации. Управляет внешним видом HTML-элементов во время анимации. Использует синтаксис объекта.
state() Создает именованный набор CSS-стилей, которые должны применяться при успешном переходе в заданное состояние. Затем на это состояние можно ссылаться по имени в других функциях анимации.
animate() Определяет информацию о времени для перехода. Необязательные значения для delay и easing. Может содержать вызовы style() внутри.
transition() Определяет последовательность анимации между двумя указанными состояниями. Использует синтаксис массива.
keyframes() Позволяет последовательно менять стили в течение заданного интервала времени. Используется в animate(). Может включать несколько вызовов style() в каждом keyframe(). Использует синтаксис массива.
group() Определяет группу шагов анимации (внутренняя анимация), которые должны выполняться параллельно. Анимация продолжается только после завершения всех внутренних шагов анимации. Используется внутри sequence() или transition().
query() Находит один или несколько внутренних элементов HTML внутри текущего элемента.
sequence() Определяет список шагов анимации, которые выполняются последовательно, один за другим.
stagger() Устанавливает время начала анимации для нескольких элементов.
animation() Создает многократно используемую анимацию, которая может быть вызвана из другого места. Используется вместе с useAnimation().
useAnimation() Активирует многоразовую анимацию. Используется с animation().
animateChild() Позволяет запускать анимацию на дочерних компонентах в те же временные рамки, что и на родительском.

Больше об анимации в Angular

Вам также может быть интересно следующее:

Посмотрите эту презентацию, показанную на конференции AngularConnect в ноябре 2017 года, и сопутствующий исходный код.

Комментарии