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 !
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 une animation 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.
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 !).
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 .
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 !
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 !
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 avec sequence .
É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 avec useAnimation .
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 !