Mit Beispielen erläuterte Winkelanimationen

Warum Animationen verwenden?

Moderne Webkomponenten verwenden häufig Animationen. Cascading Style-Sheets (CSS) bieten Entwicklern die Möglichkeit, beeindruckende Animationen zu erstellen. Eigenschaftsübergänge, eindeutig benannte Animationen und mehrteilige Keyframes sind mit CSS möglich. Die animierbaren Möglichkeiten sind dank CSS endlos.

In einer modernen Webanwendung lenkt die Animation die Aufmerksamkeit des Benutzers. Gute Animationen sollen die Aufmerksamkeit des Benutzers auf zufriedenstellende und produktive Weise lenken. Animationen sollten den Benutzer nicht stören.

Animationen bieten Feedback in Form von Bewegung. Sie zeigen dem Benutzer, dass die Anwendung ihre Anforderungen aktiv bearbeitet. Etwas so Einfaches wie ein sichtbarer Tastendruck oder ein Lader, wenn die Anwendung geladen werden muss, erregt die Aufmerksamkeit des Benutzers.

Animationen werden in Angulars Fall immer relevanter. Google entwickelt Angular und fördert gleichzeitig die Material Design-Philosophie. Es fördert prägnante Benutzeroberflächen (UI), die durch animiertes Benutzerfeedback ergänzt werden. Webanwendungen fühlen sich dadurch etwas lebendig und unterhaltsam an.

Die Angular-Community entwickelt eine zentrale Widget-Bibliothek namens Material2. Dieses Projekt fügt Angular eine Vielzahl von Widget-Modulen hinzu. Die meisten von ihnen enthalten Animationen. Um zu verstehen, wie sie funktionieren, wird in diesem Artikel empfohlen, CSS-Animationen zu studieren, bevor Sie weiterlesen.

Angular Animations ist die optimierte Version des Frameworks von CSS. CSS ist die Kerntechnologie für Angular-Animationen, die im Webbrowser ausgeführt werden. CSS geht jedoch über den Rahmen dieses Artikels hinaus. Es ist Zeit, Angular-Animationen direkt anzugehen.

Animationen einrichten

Vor dem Animieren BrowserAnimationsModulemuss das in das Import-Array des Root-Moduls aufgenommen werden. Es ist erhältlich bei @angular/platform-browser/animations. Dieses NgModule stellt sicher, dass Animationen für die jeweilige Plattform funktionieren. In diesem Artikel wird für jedes Beispiel der Standard-Webbrowser angenommen.

Winkelanimationen werden innerhalb der @ComponentMetadaten deklariert . @Componentdekoriert eine Klasse, um sie als Bestandteil von Angular zu unterscheiden. Die Metadaten enthalten Komponentenkonfigurationen einschließlich des animations: []Felds. Jedes Array-Element aus diesem Feld repräsentiert einen Animationsauslöser ( AnimationTriggerMetadata).

Animationen sind exklusiv für ihre Host-Komponente über die Metadaten des Dekorateurs. Animationen können nur in der Vorlage der Hostkomponente verwendet werden. Animationen erben nicht an die untergeordneten Elemente der Komponente. Hierfür gibt es eine einfache Lösung.

Sie können jederzeit eine separate Datei erstellen, die ein Array exportiert. Jede Komponentenklasse kann dieses Array vom Anfang ihrer Hostdatei importieren. Das importierte Array-Token wird dann in die Animationsmetadaten der Komponente aufgenommen. Wiederholen Sie diesen Vorgang für alle anderen Komponenten, für deren Animationsmetadaten dasselbe Array erforderlich ist.

Mit der Inhaltsprojektion können Sie Animationen auf das Inhalts-DOM (Document Object Model) von Komponente A anwenden. Komponente B, die diesen Inhalt umschließt DOM kann den Inhalt in eine eigene Vorlage projizieren. Sobald dies der Fall ist, werden die Animationen von Komponente A nicht negiert. Komponente B enthält die Animationen von A durch Inhaltsprojektion.

OK. Sie wissen, wie Sie Animationen einrichten und wo Sie sie deklarieren. Die Implementierung ist der nächste Schritt.

Animationsmethoden

Winkelanimationen verwenden eine Reihe von Methodenaufrufen, aus denen importiert werden kann @angular/animations. Jedes Element des @ComponentAnimationsarrays beginnt als einzelne Methode. Seine Argumente enträtseln sich als Folge von Methodenaufrufen höherer Ordnung. Die folgende Liste zeigt einige der Methoden zum Erstellen von Angular-Animationen.

  • trigger(selector: string, AnimationMetadata[])

kehrt zurück AnimationTriggerMetadata

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

kehrt zurück AnimationStateMetadata

  • style(CSSKeyValues: object)

kehrt zurück AnimationStyleMetadata

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

kehrt zurück AnimationAnimateMetadata

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

kehrt zurück AnimationTransitionMetadata

Es gibt sicherlich mehr Methoden zur Auswahl, aber diese fünf Methoden behandeln die Grundlagen. Der Versuch, diese Kernmethoden als Liste zu verstehen, hilft nicht viel. Aufzählungsweise Erklärungen, gefolgt von einem Beispiel, machen dies besser.

Trigger (Selektor: String, AnimationMetadata [])

Die trigger(...)Methode kapselt ein einzelnes Element der Animation innerhalb des Animationsarrays.

Das erste Argument selector: stringder Methode entspricht dem [@selector]Mitgliedsattribut. Es verhält sich wie eine Attributanweisung in der Komponentenvorlage. Es verbindet das Animationselement im Wesentlichen über eine Attributauswahl mit der Vorlage.

Das zweite Argument ist ein Array, das eine Liste der anwendbaren Animationsmethoden enthält. Das trigger(...)hält es insgesamt in einem einzigen Array.

state (Daten: Zeichenfolge, AnimationStyleMetadata, Optionen?: Objekt)

Die state(...)Methode definiert den Endzustand der Animation. Nach Abschluss einer Animation wird eine Liste der CSS-Eigenschaften auf das Zielelement angewendet. Auf diese Weise entspricht das CSS des animierten Elements der Auflösung der Animation.

Das erste Argument entspricht dem Wert der Daten, die an die Animationsbindung gebunden sind. Das heißt, der [@selector]in der Vorlage gebundene Wert stimmt mit dem ersten Argument von a überein state(...). Der Wert der Daten bestimmt den Endzustand. Die Änderung des Wertes bestimmt die Art der Animation (siehe transition(...)).

Das zweite Argument enthält die CSS-Stile, die für ein Element nach der Animation gelten. Stile werden übergeben, indem style(...)die gewünschten Stile als Objekt aufgerufen und in das Argument übergeben werden.

Eine Liste von Optionen belegt optional das dritte Argument. Die Standardoptionen state(...)sollten unverändert bleiben, sofern nicht anders angegeben.

Stil (CSSKeyValues: Objekt)

Möglicherweise haben Sie dies AnimationStyleMetadatain der vorherigen Liste mehrmals bemerkt . Die style(...)Komponente gibt genau diesen Metadatentyp zurück. Überall dort, wo CSS-Stile angewendet werden, style(...)muss die Methode aufgerufen werden. Ein Objekt, das CSS-Stile enthält, steht für sein Argument.

In CSS animierbare Stile werden natürlich in die Angular- style(...)Methode übernommen. Zugegeben, mit Angular-Animationen wird für CSS plötzlich nichts Unmögliches möglich.

animieren (Timing: Zeichenfolge | Nummer, AnimationStyleMetadata | AnimationKeyframesMetadata)

Die animate(...)Funktion akzeptiert einen Timing-Ausdruck als erstes Argument. Dieses Argument beschleunigt, beschleunigt und / oder verzögert die Animation der Methode. Dieses Argument akzeptiert entweder einen Zahlen- oder einen Zeichenfolgenausdruck. Die Formatierung wird hier erklärt.

Das zweite Argument von animate(...)ist die CSS-Eigenschaft, die die Animation rechtfertigt. Dies erfolgt in Form der zurückgegebenen style(...)Methode AnimationStyleMetadata. Stellen Sie sich animate(...)die Methode vor, mit der die Animation initiiert wird.

Eine Reihe von Keyframes kann auch für das zweite Argument gelten. Keyframes ist eine erweiterte Option, die in diesem Artikel später erläutert wird. Keyframes unterscheiden verschiedene Abschnitte der Animation.

animate(...)erhält möglicherweise kein zweites Argument. In diesem Fall gilt das Animations-Timing der Methode nur für das in den state(...)Methoden wiedergegebene CSS . Eigenschaftsänderungen in den state(...)Methoden des Triggers werden animiert.

Übergang (changExpr: Zeichenfolge, AnimationMetadata | AnimationMetadata [], Optionen?: Objekt)

animate(...)initiiert eine Animation, während transition(...)bestimmt wird, welche Animation initiiert wird.

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