Maison > interface Web > js tutoriel > Angular LAB : animer des listes et utiliser AnimationBuilder pour les animations impératives

Angular LAB : animer des listes et utiliser AnimationBuilder pour les animations impératives

Barbara Streisand
Libérer: 2024-10-10 06:18:29
original
859 Les gens l'ont consulté

Angular LAB: animating lists and using AnimationBuilder for imperative animations

Saviez-vous qu'Angular inclut un système d'animation complexe ? Je trouve cela particulièrement utile lorsque je souhaite animer des éléments lorsqu'ils entrent dans l'écran ou lorsqu'ils sont détruits !

De plus, vous pouvez utiliser AnimationBuilder afin de impérativement lire, mettre en pause ou arrêter certaines animations personnalisées ! Voyons comment c'est fait.

Créer une liste

Dans cet exercice, nous commençons par créer une liste, quelque chose comme ceci :

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button (click)="addUser()">Add user</button>
    <ul>
    @for (user of users(); track user.id) {
      <li>{{ user.name }}</li>
    }
    </ul>
  `,
})
export class AppComponent {
  users = signal<User[]>([
    { id: Math.random(), name: 'Michele' }
  ]);

  addUser() {
    this.users.update(users => [...users, { id: Math.random(), name: 'New user' }]);
  }
}
Copier après la connexion

Remarquez que nous avons inclus un bouton qui ajoute un utilisateur à la liste !

Animer la liste

Maintenant, et si nous voulons animer le nouvel utilisateur qui sera ajouté ? Tout d'abord, nous voulons dire à Angular que nous souhaitons utiliser son système d'animation en le fournissant dans votre configuration principale :

import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';

bootstrapApplication(AppComponent, {
  providers: [
    provideAnimationsAsync(),
  ]
});
Copier après la connexion

Ensuite, nous pouvons créer notre animation :

import { trigger, transition, style, animate } from '@angular/animations';

const fadeInAnimation = trigger('fadeIn', [
  transition(':enter', [
    style({ transform: 'scale(0.5)', opacity: 0 }),
    animate(
      '.3s cubic-bezier(.8, -0.6, 0.2, 1.5)', 
      style({ transform: 'scale(1)', opacity: 1 })
    )
  ])
])
Copier après la connexion

Avec ces aides nous :

  • Création d'un déclencheur d'animation appelé fadeIn
  • Ajout d'une transition lorsque l'élément entre dans l'écran
  • Appliqué un style initial
  • Démarrage immédiat de l'animation qui se traduira par un nouveau style appliqué à l'élément

Pour plus d'informations sur comment écrire des animations, vous pouvez vous référer au guide officiel qui est génial !

Appliquons maintenant cette animation à chacun de nos éléments de la liste :

@Component({
  ...,
  template: `
    <button (click)="addUser()">Add user</button>
    <ul>
    @for (user of users(); track user.id) {
      <li @fadeIn>{{ user.name }}</li> <!-- Notice here -->
    }
    </ul>
  `,
  // Also, add the animation to the metadata of the component
  animations: [fadeInAnimation]
}) 
Copier après la connexion

Maintenant, lorsqu'un nouvel élément est ajouté, il s'anime ! Notre premier pas est fait.

Notez que pour que notre animation fonctionne correctement, Angular doit suivre chaque élément dans notre for, car sinon il pourrait finir par recréer les mêmes éléments lors de la mise à jour du modèle, ce qui entraînerait des erreurs indésirables animations. Ceci est fourni gratuitement avec la nouvelle syntaxe Control Flow car la propriété track est obligatoire, mais si vous utilisez d'anciennes versions d'Angular avec la directive *ngFor, vous devez utiliser l'option trackBy comme ceci :

<li
  *ngFor="let user of users; trackBy: trackByUserId"
  @fadeIn
>{{ user.name }}</li>
Copier après la connexion
// A class method in your component:
trackByUserId(index, user: User) {
  return user.id;
}
Copier après la connexion

Maintenant, ajoutons un autre type d'animation à notre liste.

AnimationBuilder

Ajoutons un bouton à chaque élément de notre liste :

<li @fadeIn>
  {{ user.name }}
  <button>Make me blink</button>
</li>
Copier après la connexion

Imaginez ceci : nous voulons faire clignoter l'élément lorsque nous appuyons sur le bouton. Ce serait cool ! C'est là qu'intervient le service AnimationBuilder.

Tout d'abord, créons une directive qui sera appliquée à chaque élément. Dans cette directive, nous injecterons à la fois ElementRef et AnimationBuilder :

import { AnimationBuilder, style, animate } from '@angular/animations';

@Directive({
  selector: '[blink]',
  exportAs: 'blink', // <--- Notice
  standalone: true
})
export class BlinkDirective {

  private animationBuilder = inject(AnimationBuilder);
  private el = inject(ElementRef);
}
Copier après la connexion

Remarquez que nous avons exporté la directive : nous en verrons la raison dans quelques secondes.

Ensuite, nous pouvons créer une animation personnalisée comme celle-ci :

export class BlinkDirective {

  ...

  private animation = this.animationBuilder.build([
    style({ transform: 'scale(1)', opacity: 1 }),
    animate(150, style({ transform: 'scale(1.1)', opacity: .5 })),
    animate(150, style({ transform: 'scale(1)', opacity: 1 }))
  ]);
}
Copier après la connexion

Nous utilisons les mêmes fonctions que celles utilisées dans l'animation précédente, juste avec des styles différents.

Maintenant nous souhaitons créer un player qui réalisera l'animation sur notre élément :

export class BlinkDirective {

  ...

  private player = this.animation.create(this.el.nativeElement);
}
Copier après la connexion

Et maintenant, exposons une méthode qui démarrera réellement l'animation !

export class BlinkDirective {

  ...

  start() {
    this.player.play();
  }
}
Copier après la connexion

Il ne reste plus qu'une étape : il faut importer la directive, l'appliquer à nos éléments, la récupérer avec une variable modèle et appeler la méthode lorsque le bouton est enfoncé !

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button (click)="addUser()">Add user</button>
    <ul>
    @for (user of users(); track user.id) {
      <li @fadeIn blink #blinkDir="blink">
        {{ user.name }}
        <button (click)="blinkDir.start()">Make me blink</button>
      </li>
    }
    </ul>
  `,
  imports: [BlinkDirective],
  animations: [
    fadeInAnimation
  ]
})
Copier après la connexion

Nous pouvons récupérer l'instance de la directive et la mettre dans une variable locale car nous avons précédemment exporté la directive avec exportAs. C'est l'élément clé !

Maintenant, essayez de cliquer sur le bouton : l'élément devrait être animé correctement !

L'exercice est terminé, mais ce n'est que la pointe de l'iceberg ! AnimationPlayer dispose de nombreuses commandes que vous pouvez utiliser pour arrêter, mettre en pause et reprendre l'animation. Très cool !

interface AnimationPlayer {
  onDone(fn: () => void): void;
  onStart(fn: () => void): void;
  onDestroy(fn: () => void): void;
  init(): void;
  hasStarted(): boolean;
  play(): void;
  pause(): void;
  restart(): void;
  finish(): void;
  destroy(): void;
  reset(): void;
  setPosition(position: number): void;
  getPosition(): number;
  parentPlayer: AnimationPlayer;
  readonly totalTime: number;
  beforeDestroy?: () => any;
}
Copier après la connexion

Voici notre exemple complet si vous voulez jouer avec : mettez-le simplement dans votre fichier main.ts et voyez-le en action !

import { Component, signal, Directive, ElementRef, inject } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { trigger, transition, style, animate, AnimationBuilder } from '@angular/animations';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';

interface User {
  id: number;
  name: string;
}

@Directive({
  selector: '[blink]',
  exportAs: 'blink',
  standalone: true
})
export class BlinkDirective {

  private animationBuilder = inject(AnimationBuilder);
  private el = inject(ElementRef);

  private animation = this.animationBuilder.build([
    style({ transform: 'scale(1)', opacity: 1 }),
    animate(150, style({ transform: 'scale(1.1)', opacity: .5 })),
    animate(150, style({ transform: 'scale(1)', opacity: 1 }))
  ]);

  private player = this.animation.create(this.el.nativeElement);

  start() {
    this.player.play();
  }
}

const fadeInAnimation = trigger('fadeIn', [
  transition(':enter', [
    style({ transform: 'scale(0.5)', opacity: 0 }),
    animate(
      '.3s cubic-bezier(.8, -0.6, 0.2, 1.5)', 
      style({ transform: 'scale(1)', opacity: 1 })
    )
  ])
])

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button (click)="addUser()">Add user</button>
    <ul>
    @for (user of users(); track user.id) {
      <li @fadeIn blink #blinkDir="blink">
        {{ user.name }}
        <button (click)="blinkDir.start()">Make me blink</button>
      </li>
    }
    </ul>
  `,
  imports: [BlinkDirective],
  animations: [
    fadeInAnimation
  ]
})
export class App {
  users = signal([
    { id: Math.random(), name: 'Michele' }
  ]);

  addUser() {
    this.users.update(users => [...users, { id: Math.random(), name: 'New user' }]);
  }
}

bootstrapApplication(App, {
  providers: [
    provideAnimationsAsync()
  ]
});
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal