Toutes les animations que vous avez créées dans ce cours sont, pour l'instant, des animations simples. Les éléments sont traités en entier, et tous les éléments avec un même trigger
sont animés en même temps.
Mais les animations Angular permettent d'aller beaucoup plus loin ! Vous pouvez :
animer les éléments enfants indépendamment les uns des autres.
étaler les animations des éléments d'une liste dans le temps.
gérer des séquences d'animations.
générer des animations réutilisables et paramétrables pour améliorer la structure de votre code.
Il est temps de passer les animations de votre application au niveau suivant !
Animez les enfants
Le premier objectif est d'attribuer une animation séparée au texte contenu dans chaque commentaire : vous allez créer un effet fade-in.
Pour ceci, vous allez utiliser la fonction query
qui permet de cibler des enfants de l'élément qui comporte le trigger
:
transition(':enter', [
style({
transform: 'translateX(-100%)',
opacity: 0,
'background-color': 'rgb(201, 157, 242)',
}),
animate('250ms ease-out', style({
transform: 'translateX(0)',
opacity: 1,
'background-color': 'white',
})),
query('span', [
style({
opacity: 0
}),
animate('500ms', style({
opacity: 1
}))
]),
])
Vous ciblez les
span
du commentaire et de sa date.Vous leur attribuez un
style
et uneanimation
comme ailleurs.
Angular lit ce tableau d'animations dans l'ordre, donc pour avoir le fonctionnement souhaité, on doit faire ceci :
transition(':enter', [
query('span', [
style({
opacity: 0
}),
]),
style({
transform: 'translateX(-100%)',
opacity: 0,
'background-color': 'rgb(201, 157, 242)',
}),
animate('250ms ease-out', style({
transform: 'translateX(0)',
opacity: 1,
'background-color': 'white',
})),
query('span', [
animate('500ms', style({
opacity: 1
}))
]),
])
Comme ça, le texte est invisible dès le départ, et son fade-in a lieu après l'arrivée du bloc du commentaire.
Gérez une séquence d'animations
Prochain objectif : animer à deux vitesses différentes les deux span
de chaque commentaire, mais en lançant ces animations en même temps.
Premièrement, il faut pouvoir cibler les deux span
indépendamment. Je vous propose de leur ajouter des classes CSS :
<span class="comment-text" mat-line>{{ comment.comment }}</span>
<span class="comment-date" mat-line>{{ comment.createdDate | timeAgo }}</span>
Comme ça, le premier query
pour définir leur opacité à 0 devient :
query('.comment-text, .comment-date', [
style({
opacity: 0
})
]),
Si vous ajoutez ensuite ces animations à la place de l'animation générale des span
:
query('.comment-text', [
animate('250ms', style({
opacity: 1
}))
]),
query('.comment-date', [
animate('500ms', style({
opacity: 1
}))
]),
Les textes sont animés, mais puisque Angular lit les animations de haut en bas, ces animations sont déclenchées l'une à la suite de l'autre.
Pour les déclencher ensemble, Angular vous propose la fonction group
:
group([
query('.comment-text', [
animate('250ms', style({
opacity: 1
}))
]),
query('.comment-date', [
animate('500ms', style({
opacity: 1
}))
]),
])
Quand ces animations sont déclenchées en même temps, le ressenti global est plus organique (je trouve !).
Mettez des séquences dans des groupes
Par défaut, les animations Angular sont lues en série, sauf quand on utilise group
pour les lire en parallèle.
Mais qu'est-ce qui se passe lorsque l'on veut déclencher une séquence d'animations en même temps que d'autres animations ?
Par exemple, si vous voulez faire "flasher" la couleur de fond du commentaire (l'animer vers une couleur puis tout de suite animer son retour au blanc), et déclencher ce flash en même temps que les fade-in des textes ?
Pour ce type d'animation, vous allez ajouter la sequence
qui correspond au flash au group
des fade-in comme suit :
group([
sequence([
animate('250ms', style({
'background-color': 'rgb(255,7,147)'
})),
animate('250ms', style({
'background-color': 'white'
})),
]),
query('.comment-text', [
animate('250ms', style({
opacity: 1
}))
]),
query('.comment-date', [
animate('500ms', style({
opacity: 1
}))
]),
]),
Cette animation précise n'est pas très belle, soit ! Mais elle vous montre comment gérer le parallélisme de vos animations avec group
et sequence
.
Étalez les animations
Actuellement, tous les commentaires sont animés en même temps. Un effet dynamique sympa pourrait être de les faire apparaître en décalé, c'est-à-dire déclencher les animations à des écarts de X millisecondes les unes après les autres.
Avec seulement le trigger listItem
, ce genre de comportement n'est pas possible. Du coup, vous allez créer un nouveau trigger qui viendra se placer sur le parent mat-list
:
trigger('list', []),
<mat-list *ngIf="comments.length" @list>
Ce qui vous intéresse, c'est l'arrivée dans le DOM de cet élément, donc vous allez utiliser une transition "depuis le vide", et il faudra cibler les enfants mat-list-item
à animer.
Vous pourriez utiliser leur sélecteur HTML, mais je vous propose une autre approche :
trigger('list', [
transition(':enter', [
query('@listItem', [
])
])
]),
Ici, vous ciblez tous les enfants dotés du trigger listItem
, donc c'est parfait !
Pour déclencher les animations d'un élément enfant, vous allez utiliser animateChild
, et pour décaler ces déclenchements dans le temps, vous allez utiliser stagger
:
trigger('list', [
transition(':enter', [
query('@listItem', [
stagger(50, [
animateChild()
])
])
])
]),
La valeur 50
correspond au nombre de millisecondes entre deux déclenchements !
Rendez vos animations réutilisables
Pour créer une animation réutilisable, vous allez utiliser la méthode animation
.
Dans shared
, créez un dossier animations
. La première animation que vous allez déporter correspond au "flash", donc créez un fichier flash.animation.ts
:
import { animate, animation, sequence, style } from '@angular/animations';
export const flashAnimation = animation([
sequence([
animate('250ms', style({
'background-color': 'rgb(201, 157, 242)'
})),
animate('250ms', style({
'background-color': 'white'
})),
]),
])
Vous pouvez maintenant remplacer cette sequence
dans CommentsComponent par :
useAnimation(flashAnimation)
et vous aurez exactement le même comportement.
Faites de même avec ces lignes :
style({
transform: 'translateX(-100%)',
opacity: 0,
'background-color': 'rgb(201, 157, 242)',
}),
animate('250ms ease-out', style({
transform: 'translateX(0)',
opacity: 1,
'background-color': 'white',
})),
en créant slide-and-fade.animation.ts
:
import { animate, animation, style } from '@angular/animations';
export const slideAndFadeAnimation = animation([
style({
transform: 'translateX(-100%)',
opacity: 0,
'background-color': 'rgb(201, 157, 242)',
}),
animate('250ms ease-out', style({
transform: 'translateX(0)',
opacity: 1,
'background-color': 'white',
})),
]);
Vous pouvez donc les remplacer dans CommentsComponent par :
useAnimation(slideAndFadeAnimation)
Ces animations sont maintenant réutilisables, mais on peut mieux faire : on peut les rendre paramétrables.
Pour créer un paramètre dans une animation, on utilise la string interpolation, mais à l'intérieur des strings :
import { animate, animation, sequence, style } from '@angular/animations';
export const flashAnimation = animation([
sequence([
animate('{{ time }}', style({
'background-color': '{{ flashColor }}'
})),
animate('{{ time }}', style({
'background-color': 'white'
})),
]),
])
Cette syntaxe fait que flashAnimation
accepte deux paramètres : time
et flashColor
.
Pour passer des arguments à ces paramètres depuis les components, vous ajoutez un objet de configuration à useAnimation
:
useAnimation(flashAnimation, {
params: {
time: '250ms',
flashColor: 'rgb(249,179,111)'
}
}),
Vous pouvez faire de même pour slideAndFadeAnimation
:
import { animate, animation, style } from '@angular/animations';
export const slideAndFadeAnimation = animation([
style({
transform: 'translateX(-100%)',
opacity: 0,
'background-color': '{{ startColor }}',
}),
animate('{{ time }} ease-out', style({
transform: 'translateX(0)',
opacity: 1,
'background-color': 'white',
})),
]);
Et dans le component :
useAnimation(slideAndFadeAnimation, {
params: {
time: '5004ms',
startColor: 'rgb(201, 157, 242)'
}
}),
Ainsi, vous avez créé deux animations réutilisables et paramétrables, deux mots que nous aimons tous entendre lorsqu'il s'agit de nos outils de développement !
En résumé
Utilisez
query
pour cibler les différents enfants de l'élément animé.Déclenchez des animations en parallèle avec
group
, ou en série avecsequence
.Étalez des animations de liste avec
stagger
.Déclenchez l'animation d'un élément enfant avec
animateChild
.Rendez vos animations réutilisables avec
animation
, et utilisez-les avecuseAnimation
.Ajoutez des paramètres à vos animations avec la string interpolation, et passez des arguments pour ces paramètres via un objet de configuration passé à
useAnimation
.
Pour terminer cette deuxième partie, faites le quiz suivant. Après, on se retrouve dans la prochaine partie pour parler des formulaires !