Animacje odgrywają ważną rolę w obszarze user experience. Nie tylko usprawniają warstwę wizualną, ale posiadają także praktyczne zastosowania. Są one dość powszechne, więc każdy Angular Developer powinien być z nimi zaznajomiony.
W artykule wyjaśnię jak programistycznie kontrolować animacje w celu usprawnienia doświadczeń użytkownika.
Jaki jest cel korzystania z animacji?
Wiele firm wykorzystuje animacje aby wspomóc użytkownika w poruszaniu się po aplikacji, ułatwić proces przekazywania informacji oraz wyjaśnić proste procesy użytkownikowi.
Do najczęstszych przykładów wykorzystania animacji można zaliczyć hover oraz click. Oprócz zmiany kursora w pointera, dodanie animacji hover do klikalnych elementów jest szybką metodą zakomunikowania użytkownikowi, że dany element jest klikalny. Z drugiej strony, animacja kliknięcia (np. efekt ripple na buttonach Angular Materiala) zapewnia użytkownikowi natychmiastową informację o tym, że aplikacja zarejestrowała wykonaną przez niego akcję.
Jak dodać animację do aplikacji angularowej?
Jest wiele sposobów na to, aby dodać animację do aplikacji, łącznie z wbudowanym modułem animacji, który może być wykorzystany bez konieczności instalowania dodatkowych zależności.
Animacje w angularze są zazwyczaj używane z wykorzystaniem tablicy `animations` w dekoratorze `Component`. Animacje te są następnie uruchamiane są poprzez zastosowanie dyrektyw animacji (z prefiksem `@`, takie jak `@slideIn` czy `@fadeOut`) na docelowym elemencie.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { trigger, style, animate, transition } from '@angular/animations';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'app-root'
template: `
<div class="card-container">
<div *ngIf="cardIsDisplayed" @fadeSlideInOut class="demo-card"></div>
</div>
`,
animations: [
trigger('fadeSlideInOut', [
transition(':enter', [
style({ opacity: 0, transform: 'translateY(10px)' }),
animate('500ms', style({ opacity: 1, transform: 'translateY(0)' })),
]),
transition(':leave', [
animate('500ms', style({ opacity: 0, transform: 'translateY(10px)' })),
]),
]),
],
})
export class AppComponent {
cardIsDisplayed = true;
toggleCard(): void {
this.cardIsDisplayed = !this.cardIsDisplayed;
}
}
To podejście pokrywa większość przypadków użycia oraz jest wygodnym sposobem na dodanie animacji do twojej aplikacji angularowej.
Jak edytować animacje w aplikacji angularowej?
Angular Animations zawiera klasę `AnimationBuilder`, dzięki której można tworzyć animacje programistycznie.
Oprócz podstawowych funkcji Angular Animations, zaprogramowane animacje za pośrednictwem `AnimationPlayer` zawierają dodatkowe funkcje do kontrolowania animacji, które nie są możliwe przy użyciu podejścia szablonowego. Funkcje te obejmują:
- `pause` – wstrzymuje animacje
- `finish` – kończy animacje
- `restart` – wznawia wstrzymaną animację
- `destroy`- niszczy animacje
- `reset` – resetuje animacje do stanu pierwotnego
Klasa `AnimationPlayer` także dostarcza callbacki dla kluczowych eventów animacji, takich jak:
- `onStart` – wywołana podczas startu animacji
- `onDone` – wywołana przy zakończeniu animacji (automatycznie bądź przez wywołanie funkcji `finish` na uruchomionej aplikacji)
- `onDestroy` – wywołana po zniszczeniu animacji (kiedy wywoływana jest funkcja `destroy`)
Możesz również przekazać callback do funkcji `beforeDestroy` jeżeli chcesz wykonać kod przed zniszczeniem animacji.
Podstawowe wykorzystanie
Spójrzmy na to, jak możemy wykorzystać `AnimationBuilder` oraz `AnimationPlayer` w celu uruchomienia animacji.
Zacznijmy od stworzenia docelowego elementu oraz kilku przycisków do kontrolowania animacji.
```html
<!-- app.component.html –>
<div class="animation-demo-container">
<div class="card-container">
<div #demoCard class="demo-card"></div>
</div>
<div class="demo-controller-container">
<button class="demo-button" (click)="playAnimation()">Play</button>
<button class="demo-button" (click)="pauseAnimation()">Pause</button>
<button class="demo-button" (click)="stopAnimation()">Stop</button>
<button class="demo-button" (click)="resetAnimation()">Reset</button>
</div>
</div>
```
Dodajmy kilka styli do naszego komponentu:
```scss
// app.component.scss
.animation-demo-container {
border-radius: 0.5rem;
border-width: 1px;
border-color: rgb(14 116 144);
background-color: rgb(30 41 59);
display: flex;
flex-direction: column;
min-height: 350px;
overflow: auto;
.card-container {
flex-grow: 1;
padding: 1.25rem;
.demo-card {
width: 10rem;
height: 10rem;
border-radius: 0.5rem;
background-color: rgb(125 211 252);
}
}
.demo-controller-container {
display: flex;
flex-direction: row;
padding: 1rem 1.25rem;
border-radius: 0 0 0.5rem 0.5rem;
gap: 0.75rem;
.demo-button {
background-color: rgb(255, 255, 255);
color: rgb(15 23 42);
border-radius: 0.25rem;
padding: 0.5rem 0.75rem;
font-weight: 500;
}
}
}
```
Przejdźmy teraz do animacji. Najpierw będziemy musieli uzyskać referencję do animowanego elementu. W tym celu użyjemy dekoratora `ViewChild` i przekażemy identyfikator elementu (`#demoCard`), który zdefiniowaliśmy wcześniej, aby uzyskać do niego dostęp.
```typescript
// app.component.ts
import { Component, ElementRef, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [‘./app.component.scss’]
})
export class AppComponent {
@ViewChild('demoCard') demoCard: ElementRef | undefined;
}
```
Dodaj klasę `AnimationBuilder` i utwórz prywatną funkcję, aby zbudować animację i utworzyć instancję `AnimationPlayer`, której będziemy używać do uruchamiania naszych animacji.
```typescript
// app.component.ts
import { Component, ElementRef, ViewChild, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'app-root,
templateUrl: './app.component.html',
styleUrls: [‘./app.component.scss’]
})
export class AppComponent {
@ViewChild('demoCard') demoCard: ElementRef | undefined;
private animationBuilder = inject(AnimationBuilder);
private animationPlayer: AnimationPlayer | undefined;
private getAnimationPlayer(): AnimationPlayer | undefined {
if (!this.demoCard?.nativeElement) {
return;
}
if (!this.animationPlayer) {
const factory = this.animationBuilder.build(
[
style({ transform: 'rotate(0deg)' }),
animate('1000ms cubic-bezier(0.175, 0.885, 0.32, 1.275)', style({ transform: 'rotate(360deg)' }))
]
);
this.animationPlayer = factory.create(this.demoCard.nativeElement);
}
return this.animationPlayer;
}
}
```
Na koniec stwórzmy funkcje play, stop, pause i reset. Funkcje te będa pobierać `AnimationPlayer` poprzez wywołanie `getAnimationPlayer()`, a następnie będą wykonywać odpowiednie metody.
```typescript
// app.component.ts
import { Component, ElementRef, ViewChild, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'app-root,
templateUrl: './app.component.html',
styleUrls: [‘./app.component.scss’]
})
export class AppComponent {
@ViewChild('demoCard') demoCard: ElementRef | undefined;
private animationBuilder = inject(AnimationBuilder);
private animationPlayer: AnimationPlayer | undefined;
playAnimation(): void {
const player = this.getAnimationPlayer();
if (!player) {
return;
}
player.play();
}
pauseAnimation(): void {
const player = this.getAnimationPlayer();
if (!player || !player.hasStarted) {
return;
}
player.pause();
}
stopAnimation(): void {
const player = this.getAnimationPlayer();
if (!player || !player.hasStarted) {
return;
}
player.finish();
}
resetAnimation(): void {
const player = this.getAnimationPlayer();
if (!player || !player.hasStarted) {
return;
}
player.reset();
}
private getAnimationPlayer(): AnimationPlayer | undefined {
if (!this.demoCard?.nativeElement) {
return;
}
if (!this.animationPlayer) {
const factory = this.animationBuilder.build(
[
style({ transform: 'rotate(0deg)' }),
animate('1000ms cubic-bezier(0.175, 0.885, 0.32, 1.275)', style({ transform: 'rotate(360deg)' }))
]
);
this.animationPlayer = factory.create(this.demoCard.nativeElement);
}
return this.animationPlayer;
}
}
```
Jeżeli postępowałeś zgodnie z instrukcjami, powinieneś uzyskać następujące animacje:

Możesz odwiedzić Angular Animations Explorer aby zobaczyć live demo.
Podsumowując
Istnieje wiele sposobów na korzystanie z Angular Animations, z których każdy ma swoje idealne przypadki użycia. Jeżeli chcesz jedynie wywołać animacje, wybierz prostsze podejście szablonowe. Jeśli jednak potrzebujesz bardziej szczegółowej kontroli, użyj podejścia programistycznego, używając `AnimationBuilder` oraz `AnimationPlayer`. Możesz również sprawdzić Angular Animations Explorer, aby zobaczyć inne podejścia do dodawania animacji w Angularze.
Jeżeli interesują cie takie treści lub masz jakieś pytania, zostaw komentarz bądź skontaktuj się ze mną na Twitterze @williamjuan27.