Animations angulaires expliquées avec des exemples

Pourquoi utiliser des animations?

Les composants Web modernes utilisent fréquemment des animations. Les feuilles de style en cascade (CSS) fournissent aux développeurs les outils nécessaires pour créer des animations impressionnantes. Les transitions de propriétés, les animations au nom unique, les images clés en plusieurs parties sont possibles avec CSS. Les possibilités animables sont infinies grâce au CSS.

Dans une application Web moderne, l'animation attire l'attention de l'utilisateur. Les bonnes animations cherchent à guider l'attention de l'utilisateur de manière satisfaisante et productive. Les animations ne doivent pas être gênantes pour l'utilisateur.

Les animations offrent des retours sous forme de mouvement. Ils montrent à l'utilisateur que l'application traite activement ses demandes. Quelque chose d'aussi simple qu'une pression sur un bouton visible ou un chargeur lorsque l'application doit se charger attire l'attention de l'utilisateur.

Les animations continuent de devenir de plus en plus pertinentes dans le cas d'Angular. Google développe Angular tout en promouvant la philosophie Material Design. Il encourage les interfaces utilisateur (UI) concises complétées par des commentaires animés des utilisateurs. Cela rend les applications Web un peu vivantes et amusantes à utiliser.

La communauté Angular développe une bibliothèque de widgets principale appelée Material2. Ce projet ajoute une variété de modules de widgets à Angular. La plupart d'entre eux comportent des animations. Pour comprendre leur fonctionnement, cet article recommande d'étudier les animations CSS avant de poursuivre la lecture.

Les animations angulaires sont la version simplifiée du framework de ce que CSS fournit nativement. CSS est la technologie de base pour les animations angulaires se produisant dans le navigateur Web. Le CSS sort cependant du cadre de cet article. Il est temps de s'attaquer de front aux animations angulaires.

Configurer des animations

Avant l'animation, le BrowserAnimationsModuledoit inclure dans le tableau des importations du module racine. Il est disponible à partir de @angular/platform-browser/animations. Ce NgModule assure le fonctionnement des animations pour la plateforme donnée. Cet article suppose le navigateur Web standard pour chaque exemple.

Les animations angulaires sont déclarées dans les @Componentmétadonnées. @Componentdécore une classe pour la distinguer en tant que composant de Angular. Ses métadonnées contiennent des configurations de composants, y compris le animations: []champ. Chaque élément de tableau de ce champ représente un déclencheur d'animation ( AnimationTriggerMetadata).

Les animations sont exclusives à leur composant hôte via les métadonnées du décorateur. Les animations ne peuvent être utilisées que dans le modèle du composant hôte. Les animations n'héritent pas des enfants du composant. Il existe une solution de contournement facile pour cela.

Vous pouvez toujours créer un fichier distinct qui exporte un tableau. Toute classe de composant peut importer ce tableau à partir du haut de son fichier hôte. Le jeton de tableau importé entre ensuite dans les métadonnées d'animation du composant. Répétez ce processus pour tous les autres composants nécessitant le même tableau dans leurs métadonnées d'animation.

La projection de contenu vous permet d'appliquer des animations au DOM de contenu du composant A (Document Object Model). Le composant B encapsulant ce contenu DOM peut projeter le contenu dans son propre modèle. Une fois que c'est le cas, les animations du composant A ne s'annulent pas. Le composant B incorpore les animations de A via la projection de contenu.

D'ACCORD. Vous savez comment configurer les animations et où les déclarer. La mise en œuvre est la prochaine étape.

Méthodes d'animation

Les animations angulaires utilisent une série d'appels de méthode importables depuis @angular/animations. Chaque élément du @Componenttableau d'animations commence comme une méthode unique. Ses arguments se décomposent comme une séquence d'appels de méthode d'ordre supérieur. La liste suivante montre certaines des méthodes utilisées pour créer des animations angulaires.

  • trigger(selector: string, AnimationMetadata[])

Retour AnimationTriggerMetadata

  • state(data: string, AnimationStyleMetadata, options?: object)

Retour AnimationStateMetadata

  • style(CSSKeyValues: object)

Retour AnimationStyleMetadata

  • animate(timing: string|number, AnimationStyleMetadata|KeyframesMetadata)

Retour AnimationAnimateMetadata

  • transition(stateChange: string, AnimationMetadata|AnimationMetadata[], options?: object)

Retour AnimationTransitionMetadata

Bien qu'il existe certainement plus de méthodes parmi lesquelles choisir, ces cinq méthodes gèrent les bases. Essayer de comprendre ces méthodes de base sous forme de liste n'aide pas beaucoup. Des explications puce par puce suivies d'un exemple en donneront un meilleur sens.

trigger (sélecteur: chaîne, AnimationMetadata [])

La trigger(...)méthode encapsule un seul élément d'animation dans le tableau d'animations.

Le premier argument de la méthode selector: stringcorrespond à l' [@selector]attribut membre. Il agit comme une directive d'attribut dans le modèle de composant. Il connecte essentiellement l'élément d'animation au modèle via un sélecteur d'attribut.

Le deuxième argument est un tableau contenant une liste de méthodes d'animation applicables. Le trigger(...)garde tout dans un seul tableau.

état (données: chaîne, AnimationStyleMetadata, options ?: objet)

La state(...)méthode définit l'état final de l'animation. Il applique une liste de propriétés CSS à l'élément cible après la fin d'une animation. C'est ainsi que le CSS de l'élément animé correspond à la résolution de l'animation.

Le premier argument correspond à la valeur des données liées à la liaison d'animation. Autrement dit, la valeur liée à [@selector]dans le modèle correspond au premier argument de a state(...). La valeur des données détermine l'état final. Le changement de valeur détermine les moyens d'animation (voir transition(...)).

Le deuxième argument héberge les styles CSS qui s'appliquent à une post-animation d'élément. Les styles sont transmis en invoquant style(...)et en passant dans son argument les styles souhaités en tant qu'objet.

Une liste d'options occupe éventuellement le troisième argument. Les state(...)options par défaut doivent rester inchangées, sauf indication contraire.

style (CSSKeyValues: objet)

Vous avez peut-être remarqué AnimationStyleMetadataplusieurs fois dans la liste précédente. Le style(...)composant renvoie ce type exact de métadonnées. Partout où les styles CSS s'appliquent, la style(...)méthode doit être appelée. Un objet contenant des styles CSS remplace son argument.

Bien sûr, les styles animables en CSS sont transférés dans la style(...)méthode Angular . Certes, rien d'impossible pour CSS devient soudainement possible avec les animations angulaires.

animer (minutage: chaîne | nombre, AnimationStyleMetadata | AnimationKeyframesMetadata)

La animate(...)fonction accepte une expression de synchronisation comme premier argument. Cet argument dure, accélère et / ou retarde l'animation de la méthode. Cet argument accepte une expression numérique ou chaîne. Le formatage est expliqué ici.

Le deuxième argument de animate(...)est la propriété CSS garantissant l'animation. Cela prend la forme de la style(...)méthode qui retourne AnimationStyleMetadata. Pensez animate(...)à la méthode qui lance l'animation.

Une série d'images clés peut également s'appliquer au deuxième argument. Les images clés sont une option plus avancée que cet article explique plus tard. Les images clés distinguent différentes sections de l'animation.

animate(...)peut ne pas recevoir un deuxième argument. Dans ce cas, le minutage de l'animation de la méthode s'applique uniquement au CSS reflété dans les state(...)méthodes. Les changements de propriété dans les state(...)méthodes du déclencheur s'animeront.

transition (changExpr: chaîne, AnimationMetadata | AnimationMetadata [], options ?: objet)

animate(...)lance une animation tandis que transition(...)détermine quelle animation démarre.

The first argument consists of a unique form of micro-syntax. It denotes a change in state (or change in data) taking place. The data bound to the template animation binding ([selector]="value") determines this expression. The upcoming section titled “Animation State” explains this concept a bit further.

The second argument of transition(...) comprises AnimationMetadata (returned by animate(...)). The argument accepts either an array of AnimationMetadata or a single instance.

The first argument’s value matches against the value of the data bound in the template ([selector]="value") . If a perfect match occurs, the argument evaluates successfully. The second argument then initiates an animation in response to the success of the first.

A list of options optionally occupies the third argument. The default transition(...) options should remain unchanged unless reasoned otherwise.

Animation Example

import { Component, OnInit } from '@angular/core'; import { trigger, state, style, animate, transition } from '@angular/animations'; @Component({ selector: 'app-example', template: ` 

Click the button to change its color!

Toggle Me! // animation binding `, animations: [ // metadata array trigger('toggleClick', [ // trigger block state('true', style({ // final CSS following animation backgroundColor: 'green' })), state('false', style({ backgroundColor: 'red' })), transition('true => false', animate('1000ms linear')), // animation timing transition('false => true', animate('1000ms linear')) ]) ] // end of trigger block }) export class ExampleComponent { isGreen: string = 'true'; toggleIsCorrect() { this.isGreen = this.isGreen === 'true' ? 'false' : 'true'; // change in data-bound value } }

The above example performs a very simple color swap with each button click. Of course, the color transitions quickly in a linear fade as per animate('1000ms linear'). The animation binds to the button by matching the first argument of trigger(...) to the [@toggleClick] animation binding.

The binding binds to the value of isGreen from the component class. This value determines the resulting color as set by the two style(...) methods inside the trigger(...) block. The animation binding is one-way so that changes to isGreen in the component class notify the template binding. That is, the animation binding [@toggleClick].

The button element in the template also has a click event bound to it. Clicking the button causes isGreen to toggle values. This changes the component class data. The animation binding picks up on this and invokes its matching trigger(...) method. The trigger(...) lies within the animations array of the component’s metadata. Two things occur upon the trigger’s invocation.

The first occurrence concerns the two state(...) methods. The new value of isGreen matches against a state(...) method’s first argument. Once it matches, the CSS styles of style(...) apply to the final state of the animation binding’s host element. `The final state takes effect following all animation.

Now for the second occurrence. The data change that invoked the animation binding compares across the two transition(...) methods. One of them matches the change in data to their first argument. The first button click caused isGreen to go from ‘true’ to ‘false’ (‘true => false’). That means the first transition(...) method activates its second argument.

The animate(...) function corresponding the successfully evaluated transition(...) method initiates. This method sets the duration of the animated color fade along with the fade’s pacing. The animation executes and the button fades to red.

This process can happen any number of times following a button click. The backgroundColor of the button will cycle between green and red in a linear fade.

Animation State

The transition(...) micro-syntax is worth addressing in detail. Angular determines animations and their timing by evaluating this syntax. There exists the following state transitions. They model a changes in data bound to an animation binding.

  • ‘someValue’ => ‘anotherValue’

An animation trigger where the bound data changes from ‘someValue’ to ‘anotherValue’.

  • ‘anotherValue’ => ‘someValue’

An animation trigger where the bound data changes from ‘anotherValue’ to ‘someValue’.

  • ‘someValue’ ‘anotherValue’

Data changes from ‘someValue` to ‘anotherValue’ or vice versa.

There also exists void and * states. void indicates that the component is either entering or leaving the DOM. This is perfect for entry and exit animations.

  • ‘someValue’ => void : host component of bound data is leaving the DOM
  • void => ‘someValue’ : host component of bound data is entering the DOM

* denotes a wildcard state. Wildcard states can interpret to “any state”. This includes void plus any other change to the bound data.

Keyframes

This article touched on the basics for animating Angular applications. Advanced animation techniques exist alongside these basics. Grouping together keyframes is one such technique. Its inspired from the @keyframes CSS rule. If you have worked with CSS @keyframes, you already understand how keyframes in Angular work. It becomes just a matter of syntax

The keyframes(...) method imports from @angular/animations. It passes into the second argument of animate(...) instead of the typical AnimationStyleMetadata. The keyframes(...) method accepts one argument as an array of AnimationStyleMetadata. This can also be referred to as an array of style(...) methods.

Each keyframe of the animation goes inside the keyframes(...) array. These keyframe elements are style(...) methods supporting the offset property. offset indicates a point in the animation’s duration where its accompanying style properties should apply. Its value spans from 0 (animation start) to 1 (animation end).

import { Component } from '@angular/core'; import { trigger, state, style, animate, transition, keyframes } from '@angular/animations'; @Component({ selector: 'app-example', styles: [ `.ball { position: relative; background-color: black; border-radius: 50%; top: 200px; height: 25px; width: 25px; }` ], template: ` 

Arcing Ball Animation

Arc the Ball! `, animations: [ trigger('animateArc', [ state('true', style({ left: '400px', top: '200px' })), state('false', style({ left: '0', top: '200px' })), transition('false => true', animate('1000ms linear', keyframes([ style({ left: '0', top: '200px', offset: 0 }), style({ left: '200px', top: '100px', offset: 0.50 }), style({ left: '400px', top: '200px', offset: 1 }) ]))), transition('true => false', animate('1000ms linear', keyframes([ style({ left: '400px', top: '200px', offset: 0 }), style({ left: '200px', top: '100px', offset: 0.50 }), style({ left: '0', top: '200px', offset: 1 }) ]))) ]) ] }) export class ExampleComponent { arc: string = 'false'; toggleBounce(){ this.arc = this.arc === 'false' ? 'true' : 'false'; } }

The main difference of the above example compared to the other example is the second argument of animate(...). It now contains a keyframes(...) method hosting an array of animation keyframes. While the animation itself is also different, the technique to animate is similar.

Clicking the button causes the button to arc across the screen. The arc moves as per the keyframes(...) method’s array elements (keyframes). At the animation’s mid-point (offset: 0.50), the ball changes trajectory. It descends to its original height as it continues across the screen. Clicking the button again reverses the animation.

left and top are animatable properties after setting position: relative; for the element. The transform property can perform similar movement-based animations. transform is an expansive yet fully animatable property.

Any number of keyframes can existing between offset 0 and 1. Intricate animation sequences take the form of keyframes. They are one of many advanced techniques in Angular animations.

Animations With Host Binding

You will undoubtedly come across the situation where you want to attach an animation to the HTML element of a component itself, instead of an element in the component’s template. This requires a little more effort since you can’t just go into the template HTML and attach the animation there. Instead, you’ll have to import HostBinding and utilize that.

The minimal code for this scenario is shown below. I’ll re-use the same animation condition for the code above for consistency and I don’t show any of the actual animation code since you can easily find that above.

import { Component, HostBinding } from '@angular/core'; @Component({ ... }) export class ExampleComponent { @HostBinding('@animateArc') get arcAnimation() { return this.arc; } }

The idea behind animating the host component is pretty much the same as animating a element from the template with the only difference being your lack of access to the element you are animating. You still have to pass the name of the animation (@animateArc) when declaring the HostBinding and you still have to return the current state of the animation (this.arc). The name of the function doesn’t actual matter, so arcAnimation could have been changed to anything, as long as it doesn’t clash with existing property names on the component, and it would work perfectly fine.

Conclusion

This covers the basics of animating with Angular. Angular makes setting up animations very easy using the Angular CLI. Getting started with your first animation only requires a single component class. Remember, animations scope to the component’s template. Export your transitions array from a separate file if you plan to use it across multiple components.

Every animation utility/method exports from @angular/animations. They all work together to provide a robust system of animation inspired from CSS. There are more methods beyond what this article could cover.

Now that you know the basics, feel free to explore the links below for more on Angular animations.

More info on Angular Animations:

  • Angular Documentation
  • How to use animation with Angular 6