首頁 > web前端 > js教程 > 主體

Angular LAB:動畫列表並使用 AnimationBuilder 實作命令式動畫

Barbara Streisand
發布: 2024-10-10 06:18:29
原創
771 人瀏覽過

Angular LAB: animating lists and using AnimationBuilder for imperative animations

您知道 Angular 包含一個複雜的動畫系統嗎?當我想要在元素進入螢幕或被破壞時為其設置動畫時,我發現它特別有用!

此外,您還可以使用 AnimationBuilder 來強製播放、暫停或停止一些自訂動畫!讓我們看看它是如何完成的。

創建列表

在本練習中,我們先建立一個列表,如下所示:

@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' }]);
  }
}
登入後複製

請注意,我們新增了一個將使用者加入清單的按鈕!

動畫列表

現在,如果我們想要為要新增的使用者設定動畫該怎麼辦?首先,我們想透過在主配置中提供它來告訴 Angular 我們想要使用它的動畫系統:

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

bootstrapApplication(AppComponent, {
  providers: [
    provideAnimationsAsync(),
  ]
});
登入後複製

然後,我們可以創建我們的動畫:

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 })
    )
  ])
])
登入後複製

有了這些幫助者,我們:

  • 創建了一個名為 fadeIn 的動畫觸發器
  • 加入了元素進入螢幕時的過渡
  • 應用了初始樣式
  • 立即開始動畫,這將導致新的樣式應用於元素

更多關於如何編寫動畫的信息,可以參考官方指南,非常棒!

現在讓我們將此動畫應用到清單中的每個元素:

@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]
}) 
登入後複製

現在,當新增項目時,它會變得動畫!我們的第一步已經完成。

請注意,為了讓我們的動畫正常工作,Angular 必須追蹤for 中的每個元素,因為否則它最終可能會在更新模板時重新創建相同的元素,從而導致不必要的結果動畫。這是免費的新控制流語法,因為 track 屬性是強制性的,但如果您使用舊版本的 Angular 和 *ngFor 指令,則必須使用 trackBy 選項,如下所示:

<li
  *ngFor="let user of users; trackBy: trackByUserId"
  @fadeIn
>{{ user.name }}</li>
登入後複製
// A class method in your component:
trackByUserId(index, user: User) {
  return user.id;
}
登入後複製

現在,讓我們在清單中加入另一種類型的動畫。

動畫生成器

讓我們為清單的每個元素新增一個按鈕:

<li @fadeIn>
  {{ user.name }}
  <button>Make me blink</button>
</li>
登入後複製

想像一下:我們想讓元素在按下按鈕時閃爍。那就太酷了!這就是 AnimationBuilder 服務的用武之地。

首先,讓我們建立一個將應用於每個元素的指令。在此指令中,我們將注入 ElementRef 和 A​​nimationBuilder:

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);
}
登入後複製

請注意,我們導出了指令:我們將在幾秒鐘內找到原因。

然後,我們可以創建一個像這樣的自訂動畫:

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 }))
  ]);
}
登入後複製

我們使用的函數與先前的動畫中使用的函數相同,只是樣式不同。

現在我們要建立一個播放器,它將在我們的元素上執行動畫:

export class BlinkDirective {

  ...

  private player = this.animation.create(this.el.nativeElement);
}
登入後複製

現在讓我們公開一個真正啟動動畫的方法!

export class BlinkDirective {

  ...

  start() {
    this.player.play();
  }
}
登入後複製

只剩下一步了:我們必須導入指令,將其應用到我們的元素,使用模板變數獲取它,並在按下按鈕時調用該方法!

@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
  ]
})
登入後複製

我們可以取得指令的實例並將其放入局部變數中,因為我們之前使用exportAs導出了指令。這就是關鍵部分!

現在,嘗試點擊按鈕:該元素應該正確動畫!

練習已經完成,但這只是冰山一角! AnimationPlayer 有許多指令可用於停止、暫停和恢復動畫。非常酷!

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;
}
登入後複製

如果您想使用它,這是我們的完整範例:只需將其放入 main.ts 檔案中並查看它的實際效果!

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()
  ]
});
登入後複製

以上是Angular LAB:動畫列表並使用 AnimationBuilder 實作命令式動畫的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!