آنلاین

مقدمه‌ای بر animationهای Angular

animation توهم حرکت ایجاد می‌کند: styleهای elementهای HTML در طول زمان تغییر می‌کنند. animationهای خوش‌ساخت می‌توانند برنامه شما را قابل‌درک‌تر و جذاب‌تر کنند، اما صرفاً جنبه ظاهری ندارند. animationها از چند راه می‌توانند برنامه و تجربه کاربری را بهبود دهند:

  • بدون animation،‏ transitionهای صفحه وب ممکن است ناگهانی و آزاردهنده به نظر برسند.
  • حرکت تجربه کاربری را به‌طور چشمگیری بهبود می‌دهد؛ بنابراین animation به کاربر فرصت می‌دهد واکنش برنامه به عمل خود را تشخیص دهد.
  • animationهای مناسب به‌شکلی طبیعی توجه کاربر را به نقطه موردنیاز جلب می‌کنند.

animationها معمولاً شامل چند تبدیل style در طول زمان هستند. یک element در HTML می‌تواند جابه‌جا شود، تغییر رنگ دهد، بزرگ یا کوچک شود، محو شود یا از صفحه slide کند. این تغییرها می‌توانند هم‌زمان یا متوالی باشند و می‌توانید زمان‌بندی هر تبدیل را کنترل کنید.

سیستم animation در Angular بر قابلیت‌های CSS ساخته شده است؛ بنابراین هر propertyای را که مرورگر قابل animate بداند می‌توانید animate کنید. این موارد شامل موقعیت، اندازه، transform، رنگ، border و موارد دیگر هستند. W3C فهرستی از propertyهای قابل animate را در صفحه CSS Transitions نگهداری می‌کند.

درباره این راهنما

این راهنما قابلیت‌های پایه animation در Angular را پوشش می‌دهد تا افزودن animationهای Angular به پروژه را آغاز کنید.

شروع کار

moduleهای اصلی Angular برای animation عبارت‌اند از @angular/animations و @angular/platform-browser.

برای آغاز افزودن animationهای Angular به پروژه، moduleهای مخصوص animation را همراه با قابلیت‌های استاندارد Angular import کنید.

provideAnimationsAsync را از @angular/platform-browser/animations/async import کنید و آن را به فهرست providerها در فراخوانی تابع bootstrapApplication بیفزایید.

Enabling Animations
bootstrapApplication(AppComponent, {
  providers: [provideAnimationsAsync()],
});

برای برنامه‌های مبتنی بر NgModule،‏ BrowserAnimationsModule را import کنید تا قابلیت animation به module ریشه برنامه Angular افزوده شود.

app.module.ts
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

@NgModule({
  imports: [BrowserModule, BrowserAnimationsModule],
  declarations: [],
  bootstrap: [],
})
export class AppModule {}

اگر قصد دارید توابع مشخصی از animation را در فایل‌های component به‌کار ببرید، آن توابع را از @angular/animations import کنید.

app.ts
// #docplaster
// #docregion imports
import {Component, HostBinding, inject} from '@angular/core';
import {
  trigger,
  state,
  style,
  animate,
  transition,
  // ...
} from '@angular/animations';

// #enddocregion imports
import {ChildrenOutletContexts, RouterLink, RouterOutlet} from '@angular/router';
import {slideInAnimation} from './animations';

// #docregion decorator, toggle-app-animations, define
@Component({
  selector: 'app-root',
  templateUrl: 'app.html',
  styleUrls: ['app.css'],
  imports: [RouterLink, RouterOutlet],
  animations: [
    // #enddocregion decorator
    slideInAnimation,
    // #docregion decorator
    // #enddocregion toggle-app-animations, define
    // animation triggers go here
    // #docregion toggle-app-animations, define
  ],
})
// #enddocregion decorator, define
export class AppComponent {
  @HostBinding('@.disabled')
  public animationsDisabled = false;
  // #enddocregion toggle-app-animations

  // #docregion get-route-animations-data
  private contexts = inject(ChildrenOutletContexts);

  getRouteAnimationData() {
    return this.contexts.getContext('primary')?.route?.snapshot?.data?.['animation'];
  }
  // #enddocregion get-route-animations-data

  toggleAnimations() {
    this.animationsDisabled = !this.animationsDisabled;
  }
  // #docregion toggle-app-animations
}
// #enddocregion toggle-app-animations

در پایان این راهنما تمام توابع animation موجود را ببینید.

در فایل component، یک property مربوط به metadata با نام animations: داخل decorator مربوط به @Component() اضافه کنید. trigger تعریف‌کننده animation را داخل property مربوط به metadata یعنی animations قرار دهید.

app.ts
// #docplaster
// #docregion imports
import {Component, HostBinding, inject} from '@angular/core';
import {
  trigger,
  state,
  style,
  animate,
  transition,
  // ...
} from '@angular/animations';

// #enddocregion imports
import {ChildrenOutletContexts, RouterLink, RouterOutlet} from '@angular/router';
import {slideInAnimation} from './animations';

// #docregion decorator, toggle-app-animations, define
@Component({
  selector: 'app-root',
  templateUrl: 'app.html',
  styleUrls: ['app.css'],
  imports: [RouterLink, RouterOutlet],
  animations: [
    // #enddocregion decorator
    slideInAnimation,
    // #docregion decorator
    // #enddocregion toggle-app-animations, define
    // animation triggers go here
    // #docregion toggle-app-animations, define
  ],
})
// #enddocregion decorator, define
export class AppComponent {
  @HostBinding('@.disabled')
  public animationsDisabled = false;
  // #enddocregion toggle-app-animations

  // #docregion get-route-animations-data
  private contexts = inject(ChildrenOutletContexts);

  getRouteAnimationData() {
    return this.contexts.getContext('primary')?.route?.snapshot?.data?.['animation'];
  }
  // #enddocregion get-route-animations-data

  toggleAnimations() {
    this.animationsDisabled = !this.animationsDisabled;
  }
  // #docregion toggle-app-animations
}
// #enddocregion toggle-app-animations

animate کردن یک transition

یک transition را animate می‌کنیم که یک element در HTML را از یک state به state دیگر تغییر می‌دهد. برای مثال، می‌توانید تعیین کنید یک button بر اساس آخرین عمل کاربر Open یا Closed را نمایش دهد. وقتی button در state مربوط به open است، قابل‌مشاهده و زردرنگ است. در state مربوط به closed، نیمه‌شفاف و آبی است.

در HTML این attributeها با styleهای معمول CSS مانند color و opacity تنظیم می‌شوند. در Angular با تابع style() مجموعه‌ای از styleهای CSS را برای استفاده در animation مشخص کنید. مجموعه‌ای از styleها را در یک state مربوط به animation گردآوری کرده و نامی مانند open یا closed به آن بدهید.

برای تولید component، دستور زیر را در terminal اجرا کنید:

shell
ng g component open-close

این دستور component را در src/app/open-close.ts ایجاد می‌کند.

state و styleهای animation

با تابع state() در Angular،‏ stateهای متفاوتی را تعریف کنید که در پایان هر transition فراخوانی می‌شوند. این تابع دو آرگومان دریافت می‌کند: نامی یکتا مانند open یا closed و یک تابع style().

با تابع style() مجموعه styleهای مرتبط با نام یک state را تعریف کنید. برای attributeهای style دارای خط تیره، مانند backgroundColor، باید از camelCase استفاده کنید یا آن‌ها را مانند 'background-color' درون کوتیشن بگذارید.

ببینیم تابع state() در Angular چگونه همراه با تابع styleâپ£آ­(âپ ) برای تنظیم attributeهای style در CSS کار می‌کند. در این قطعه‌کد، چند attribute مربوط به style به‌طور هم‌زمان برای state تنظیم شده‌اند. در state مربوط به open، ارتفاع button برابر ۲۰۰ پیکسل، opacity آن ۱ و رنگ پس‌زمینه‌اش زرد است.

open-close.ts
// #docplaster
import {Component, input} from '@angular/core';
import {trigger, transition, state, animate, style, AnimationEvent} from '@angular/animations';

// #docregion component, events1
@Component({
  selector: 'app-open-close',
  // #docregion trigger-wildcard1, trigger-transition
  animations: [
    trigger('openClose', [
      // #docregion state1
      // ...
      // #enddocregion events1
      state(
        'open',
        style({
          height: '200px',
          opacity: 1,
          backgroundColor: 'yellow',
        }),
      ),
      // #enddocregion state1
      // #docregion state2
      state(
        'closed',
        style({
          height: '100px',
          opacity: 0.8,
          backgroundColor: 'blue',
        }),
      ),
      // #enddocregion state2, trigger-wildcard1
      // #docregion transition1
      transition('open => closed', [animate('1s')]),
      // #enddocregion transition1
      // #docregion transition2
      transition('closed => open', [animate('0.5s')]),
      // #enddocregion transition2, component
      // #docregion trigger-wildcard1
      transition('* => closed', [animate('1s')]),
      transition('* => open', [animate('0.5s')]),
      // #enddocregion trigger-wildcard1
      // #docregion trigger-wildcard2
      transition('open <=> closed', [animate('0.5s')]),
      // #enddocregion trigger-wildcard2
      // #docregion transition4
      transition('* => open', [animate('1s', style({opacity: '*'}))]),
      // #enddocregion transition4
      transition('* => *', [animate('1s')]),
      // #enddocregion trigger-transition
      // #docregion component, trigger-wildcard1, events1
    ]),
  ],
  // #enddocregion trigger-wildcard1
  templateUrl: 'open-close.html',
  styleUrls: ['open-close.css'],
})
// #docregion events
export class OpenClose {
  // #enddocregion events1, events, component
  logging = input(false);
  // #docregion component
  isOpen = true;

  toggle() {
    this.isOpen = !this.isOpen;
  }

  // #enddocregion component
  // #docregion events1, events
  onAnimationEvent(event: AnimationEvent) {
    // #enddocregion events1, events
    if (!this.logging) {
      return;
    }
    // #docregion events
    // openClose is trigger name in this example
    console.warn(`Animation Trigger: ${event.triggerName}`);

    // phaseName is "start" or "done"
    console.warn(`Phase: ${event.phaseName}`);

    // in our example, totalTime is 1000 (number of milliseconds in a second)
    console.warn(`Total time: ${event.totalTime}`);

    // in our example, fromState is either "open" or "closed"
    console.warn(`From: ${event.fromState}`);

    // in our example, toState either "open" or "closed"
    console.warn(`To: ${event.toState}`);

    // the HTML element itself, the button in this case
    console.warn(`Element: ${event.element}`);
    // #docregion events1
  }
  // #docregion component
}
// #enddocregion component

در state زیر یعنی closed، ارتفاع button برابر ۱۰۰ پیکسل، opacity آن ۰٫۸ و رنگ پس‌زمینه‌اش آبی است.

open-close.ts
// #docplaster
import {Component, input} from '@angular/core';
import {trigger, transition, state, animate, style, AnimationEvent} from '@angular/animations';

// #docregion component, events1
@Component({
  selector: 'app-open-close',
  // #docregion trigger-wildcard1, trigger-transition
  animations: [
    trigger('openClose', [
      // #docregion state1
      // ...
      // #enddocregion events1
      state(
        'open',
        style({
          height: '200px',
          opacity: 1,
          backgroundColor: 'yellow',
        }),
      ),
      // #enddocregion state1
      // #docregion state2
      state(
        'closed',
        style({
          height: '100px',
          opacity: 0.8,
          backgroundColor: 'blue',
        }),
      ),
      // #enddocregion state2, trigger-wildcard1
      // #docregion transition1
      transition('open => closed', [animate('1s')]),
      // #enddocregion transition1
      // #docregion transition2
      transition('closed => open', [animate('0.5s')]),
      // #enddocregion transition2, component
      // #docregion trigger-wildcard1
      transition('* => closed', [animate('1s')]),
      transition('* => open', [animate('0.5s')]),
      // #enddocregion trigger-wildcard1
      // #docregion trigger-wildcard2
      transition('open <=> closed', [animate('0.5s')]),
      // #enddocregion trigger-wildcard2
      // #docregion transition4
      transition('* => open', [animate('1s', style({opacity: '*'}))]),
      // #enddocregion transition4
      transition('* => *', [animate('1s')]),
      // #enddocregion trigger-transition
      // #docregion component, trigger-wildcard1, events1
    ]),
  ],
  // #enddocregion trigger-wildcard1
  templateUrl: 'open-close.html',
  styleUrls: ['open-close.css'],
})
// #docregion events
export class OpenClose {
  // #enddocregion events1, events, component
  logging = input(false);
  // #docregion component
  isOpen = true;

  toggle() {
    this.isOpen = !this.isOpen;
  }

  // #enddocregion component
  // #docregion events1, events
  onAnimationEvent(event: AnimationEvent) {
    // #enddocregion events1, events
    if (!this.logging) {
      return;
    }
    // #docregion events
    // openClose is trigger name in this example
    console.warn(`Animation Trigger: ${event.triggerName}`);

    // phaseName is "start" or "done"
    console.warn(`Phase: ${event.phaseName}`);

    // in our example, totalTime is 1000 (number of milliseconds in a second)
    console.warn(`Total time: ${event.totalTime}`);

    // in our example, fromState is either "open" or "closed"
    console.warn(`From: ${event.fromState}`);

    // in our example, toState either "open" or "closed"
    console.warn(`To: ${event.toState}`);

    // the HTML element itself, the button in this case
    console.warn(`Element: ${event.element}`);
    // #docregion events1
  }
  // #docregion component
}
// #enddocregion component

transitionها و زمان‌بندی

در Angular می‌توانید چند style را بدون animation تنظیم کنید. بااین‌حال، بدون تنظیمات بیشتر، button فوراً تغییر می‌کند و هیچ محوشدن، کوچک‌شدن یا نشانه دیداری دیگری از تغییر دیده نمی‌شود.

برای نرم‌ترکردن تغییر، باید یک transition مربوط به animation تعریف کنید که تغییرهای میان دو state را در یک بازه زمانی مشخص کند. تابع transition() دو آرگومان می‌پذیرد: آرگومان اول عبارتی برای جهت میان دو state و آرگومان دوم یک یا چند مرحله animate() است.

با تابع animate() مدت، تأخیر و easing یک transition و تابع style مربوط به زمان اجرای transition را تعریف کنید. همچنین با تابع animate() تابع keyframes() را برای animationهای چندمرحله‌ای تعریف کنید. این تعریف‌ها در آرگومان دوم تابع animate() قرار می‌گیرند.

metadata مربوط به animation: مدت، تأخیر و easing

تابع animate() ــ آرگومان دوم تابع transition ــ پارامترهای ورودی timings و styles را می‌پذیرد.

پارامتر timings یک عدد یا رشته سه‌بخشی دریافت می‌کند.

ts
animate(duration);

یا

ts
animate('duration delay easing');

بخش اول یعنی duration الزامی است. مدت را می‌توان به‌صورت عدد بدون کوتیشن بر حسب میلی‌ثانیه، یا رشته بر حسب ثانیه همراه با مشخص‌کننده زمان نوشت. برای مثال، یک‌دهم ثانیه را می‌توان به شکل‌های زیر بیان کرد:

100

  • عدد ساده بر حسب میلی‌ثانیه:

'100ms'

  • رشته بر حسب میلی‌ثانیه:

'0.1s'

  • رشته بر حسب ثانیه:

آرگومان دوم یعنی delay syntax مشابه duration دارد. برای مثال:

  • ۱۰۰ میلی‌ثانیه انتظار و سپس ۲۰۰ میلی‌ثانیه اجرا: '0.2s 100ms'

آرگومان سوم یعنی easing، نحوه شتاب‌گرفتن و کاهش سرعت animation هنگام runtime را کنترل می‌کند. برای مثال، ease-in باعث می‌شود animation آهسته آغاز شود و به‌تدریج سرعت بگیرد.

استفاده از منحنی کاهش سرعت برای شروع سریع و کاهش تدریجی سرعت تا توقف: '0.2s 100ms ease-out'

  • ۱۰۰ میلی‌ثانیه انتظار و ۲۰۰ میلی‌ثانیه اجرا.

استفاده از منحنی استاندارد برای شروع آهسته، شتاب‌گیری در میانه و کاهش آرام سرعت در پایان: '0.2s ease-in-out'

  • ۲۰۰ میلی‌ثانیه اجرا بدون تأخیر.

استفاده از منحنی شتاب برای شروع آهسته و رسیدن به بیشترین سرعت در پایان: '0.2s ease-in'

  • شروع فوری و اجرای ۲۰۰ میلی‌ثانیه‌ای.

این مثال transition یک‌ثانیه‌ای از state مربوط به open به closed را ارائه می‌کند.

open-close.ts
// #docplaster
import {Component, input} from '@angular/core';
import {trigger, transition, state, animate, style, AnimationEvent} from '@angular/animations';

// #docregion component, events1
@Component({
  selector: 'app-open-close',
  // #docregion trigger-wildcard1, trigger-transition
  animations: [
    trigger('openClose', [
      // #docregion state1
      // ...
      // #enddocregion events1
      state(
        'open',
        style({
          height: '200px',
          opacity: 1,
          backgroundColor: 'yellow',
        }),
      ),
      // #enddocregion state1
      // #docregion state2
      state(
        'closed',
        style({
          height: '100px',
          opacity: 0.8,
          backgroundColor: 'blue',
        }),
      ),
      // #enddocregion state2, trigger-wildcard1
      // #docregion transition1
      transition('open => closed', [animate('1s')]),
      // #enddocregion transition1
      // #docregion transition2
      transition('closed => open', [animate('0.5s')]),
      // #enddocregion transition2, component
      // #docregion trigger-wildcard1
      transition('* => closed', [animate('1s')]),
      transition('* => open', [animate('0.5s')]),
      // #enddocregion trigger-wildcard1
      // #docregion trigger-wildcard2
      transition('open <=> closed', [animate('0.5s')]),
      // #enddocregion trigger-wildcard2
      // #docregion transition4
      transition('* => open', [animate('1s', style({opacity: '*'}))]),
      // #enddocregion transition4
      transition('* => *', [animate('1s')]),
      // #enddocregion trigger-transition
      // #docregion component, trigger-wildcard1, events1
    ]),
  ],
  // #enddocregion trigger-wildcard1
  templateUrl: 'open-close.html',
  styleUrls: ['open-close.css'],
})
// #docregion events
export class OpenClose {
  // #enddocregion events1, events, component
  logging = input(false);
  // #docregion component
  isOpen = true;

  toggle() {
    this.isOpen = !this.isOpen;
  }

  // #enddocregion component
  // #docregion events1, events
  onAnimationEvent(event: AnimationEvent) {
    // #enddocregion events1, events
    if (!this.logging) {
      return;
    }
    // #docregion events
    // openClose is trigger name in this example
    console.warn(`Animation Trigger: ${event.triggerName}`);

    // phaseName is "start" or "done"
    console.warn(`Phase: ${event.phaseName}`);

    // in our example, totalTime is 1000 (number of milliseconds in a second)
    console.warn(`Total time: ${event.totalTime}`);

    // in our example, fromState is either "open" or "closed"
    console.warn(`From: ${event.fromState}`);

    // in our example, toState either "open" or "closed"
    console.warn(`To: ${event.toState}`);

    // the HTML element itself, the button in this case
    console.warn(`Element: ${event.element}`);
    // #docregion events1
  }
  // #docregion component
}
// #enddocregion component

در قطعه‌کد بالا، عملگر => نشان‌دهنده transition یک‌طرفه و <=> نشان‌دهنده transition دوطرفه است. درون transition،‏ animate() مدت اجرای transition را مشخص می‌کند. در این حالت تغییر state از open به closed یک ثانیه طول می‌کشد که با 1s بیان شده است.

مثال زیر transition از state مربوط به closed به open را با قوس animation نیم‌ثانیه‌ای اضافه می‌کند.

open-close.ts
// #docplaster
import {Component, input} from '@angular/core';
import {trigger, transition, state, animate, style, AnimationEvent} from '@angular/animations';

// #docregion component, events1
@Component({
  selector: 'app-open-close',
  // #docregion trigger-wildcard1, trigger-transition
  animations: [
    trigger('openClose', [
      // #docregion state1
      // ...
      // #enddocregion events1
      state(
        'open',
        style({
          height: '200px',
          opacity: 1,
          backgroundColor: 'yellow',
        }),
      ),
      // #enddocregion state1
      // #docregion state2
      state(
        'closed',
        style({
          height: '100px',
          opacity: 0.8,
          backgroundColor: 'blue',
        }),
      ),
      // #enddocregion state2, trigger-wildcard1
      // #docregion transition1
      transition('open => closed', [animate('1s')]),
      // #enddocregion transition1
      // #docregion transition2
      transition('closed => open', [animate('0.5s')]),
      // #enddocregion transition2, component
      // #docregion trigger-wildcard1
      transition('* => closed', [animate('1s')]),
      transition('* => open', [animate('0.5s')]),
      // #enddocregion trigger-wildcard1
      // #docregion trigger-wildcard2
      transition('open <=> closed', [animate('0.5s')]),
      // #enddocregion trigger-wildcard2
      // #docregion transition4
      transition('* => open', [animate('1s', style({opacity: '*'}))]),
      // #enddocregion transition4
      transition('* => *', [animate('1s')]),
      // #enddocregion trigger-transition
      // #docregion component, trigger-wildcard1, events1
    ]),
  ],
  // #enddocregion trigger-wildcard1
  templateUrl: 'open-close.html',
  styleUrls: ['open-close.css'],
})
// #docregion events
export class OpenClose {
  // #enddocregion events1, events, component
  logging = input(false);
  // #docregion component
  isOpen = true;

  toggle() {
    this.isOpen = !this.isOpen;
  }

  // #enddocregion component
  // #docregion events1, events
  onAnimationEvent(event: AnimationEvent) {
    // #enddocregion events1, events
    if (!this.logging) {
      return;
    }
    // #docregion events
    // openClose is trigger name in this example
    console.warn(`Animation Trigger: ${event.triggerName}`);

    // phaseName is "start" or "done"
    console.warn(`Phase: ${event.phaseName}`);

    // in our example, totalTime is 1000 (number of milliseconds in a second)
    console.warn(`Total time: ${event.totalTime}`);

    // in our example, fromState is either "open" or "closed"
    console.warn(`From: ${event.fromState}`);

    // in our example, toState either "open" or "closed"
    console.warn(`To: ${event.toState}`);

    // the HTML element itself, the button in this case
    console.warn(`Element: ${event.element}`);
    // #docregion events1
  }
  // #docregion component
}
// #enddocregion component
  • با state() styleهایی را تعریف کنید که در پایان هر transition اعمال می‌شوند و پس از پایان animation باقی می‌مانند.
  • با transition() styleهای میانی را تعریف کنید که هنگام animation توهم حرکت ایجاد می‌کنند.
  • وقتی animationها غیرفعال‌اند، styleهای transition() ممکن است نادیده گرفته شوند، اما styleهای state() نادیده گرفته نمی‌شوند.
  • چند جفت state را در یک آرگومان transition() قرار دهید:

``ts transition('on => off, off => void'); ``

فعال‌کردن animation

یک animation برای تشخیص زمان شروع به trigger نیاز دارد. تابع trigger()،‏ stateها و transitionها را گردآوری و animation را نام‌گذاری می‌کند تا بتوانید آن را به element فعال‌کننده در template مربوط به HTML متصل کنید.

تابع trigger() نام propertyای را مشخص می‌کند که باید تغییرهای آن بررسی شوند. هنگام تغییر، trigger عمل‌های موجود در تعریف خود را آغاز می‌کند. این عمل‌ها می‌توانند transition یا توابع دیگری باشند که بعداً می‌بینیم.

در این مثال trigger را openClose می‌نامیم و به element مربوط به button متصل می‌کنیم. trigger،‏ stateهای باز و بسته و زمان‌بندی دو transition را توصیف می‌کند.

بااین‌حال، چند trigger می‌توانند هم‌زمان فعال باشند.

تعریف animation و اتصال آن به template مربوط به HTML

animationها در metadata مربوط به component کنترل‌کننده element در HTML تعریف می‌شوند. کد تعریف animationها را زیر property مربوط به animations: در decorator مربوط به @Component() قرار دهید.

open-close.ts
// #docplaster
import {Component, input} from '@angular/core';
import {trigger, transition, state, animate, style, AnimationEvent} from '@angular/animations';

// #docregion component, events1
@Component({
  selector: 'app-open-close',
  // #docregion trigger-wildcard1, trigger-transition
  animations: [
    trigger('openClose', [
      // #docregion state1
      // ...
      // #enddocregion events1
      state(
        'open',
        style({
          height: '200px',
          opacity: 1,
          backgroundColor: 'yellow',
        }),
      ),
      // #enddocregion state1
      // #docregion state2
      state(
        'closed',
        style({
          height: '100px',
          opacity: 0.8,
          backgroundColor: 'blue',
        }),
      ),
      // #enddocregion state2, trigger-wildcard1
      // #docregion transition1
      transition('open => closed', [animate('1s')]),
      // #enddocregion transition1
      // #docregion transition2
      transition('closed => open', [animate('0.5s')]),
      // #enddocregion transition2, component
      // #docregion trigger-wildcard1
      transition('* => closed', [animate('1s')]),
      transition('* => open', [animate('0.5s')]),
      // #enddocregion trigger-wildcard1
      // #docregion trigger-wildcard2
      transition('open <=> closed', [animate('0.5s')]),
      // #enddocregion trigger-wildcard2
      // #docregion transition4
      transition('* => open', [animate('1s', style({opacity: '*'}))]),
      // #enddocregion transition4
      transition('* => *', [animate('1s')]),
      // #enddocregion trigger-transition
      // #docregion component, trigger-wildcard1, events1
    ]),
  ],
  // #enddocregion trigger-wildcard1
  templateUrl: 'open-close.html',
  styleUrls: ['open-close.css'],
})
// #docregion events
export class OpenClose {
  // #enddocregion events1, events, component
  logging = input(false);
  // #docregion component
  isOpen = true;

  toggle() {
    this.isOpen = !this.isOpen;
  }

  // #enddocregion component
  // #docregion events1, events
  onAnimationEvent(event: AnimationEvent) {
    // #enddocregion events1, events
    if (!this.logging) {
      return;
    }
    // #docregion events
    // openClose is trigger name in this example
    console.warn(`Animation Trigger: ${event.triggerName}`);

    // phaseName is "start" or "done"
    console.warn(`Phase: ${event.phaseName}`);

    // in our example, totalTime is 1000 (number of milliseconds in a second)
    console.warn(`Total time: ${event.totalTime}`);

    // in our example, fromState is either "open" or "closed"
    console.warn(`From: ${event.fromState}`);

    // in our example, toState either "open" or "closed"
    console.warn(`To: ${event.toState}`);

    // the HTML element itself, the button in this case
    console.warn(`Element: ${event.element}`);
    // #docregion events1
  }
  // #docregion component
}
// #enddocregion component

پس از تعریف trigger مربوط به animation برای یک component، نام trigger را درون براکت و با پیشوند @ قرار دهید و آن را به element داخل template آن component متصل کنید. سپس trigger را با syntax استاندارد property binding در Angular به یک عبارت template متصل کنید؛ در نمونه زیر triggerName نام trigger است و expression به یک state تعریف‌شده animation ارزیابی می‌شود.

html
<div [@triggerName]="expression">…</div>

وقتی مقدار عبارت به state جدیدی تغییر کند، animation اجرا یا فعال می‌شود.

قطعه‌کد زیر trigger را به مقدار property مربوط به isOpen متصل می‌کند.

open-close.html
<!-- #docplaster -->
<!-- #docregion trigger -->
<nav>
  <button type="button" (click)="toggle()">Toggle Open/Close</button>
</nav>

<div [@openClose]="isOpen ? 'open' : 'closed'" class="open-close-container">
  <p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
</div>
<!-- #enddocregion trigger -->

در این مثال، وقتی عبارت isOpen به state تعریف‌شده open یا closed ارزیابی شود، تغییر state را به trigger با نام openClose اعلام می‌کند. سپس کد openClose تغییر state را مدیریت کرده و animation مربوط به آن را آغاز می‌کند.

برای elementهایی که وارد صفحه یا از آن خارج می‌شوند ــ یعنی در DOM درج یا از آن حذف می‌شوند ــ می‌توانید animationها را شرطی کنید. برای مثال، در template مربوط به HTML از *ngIf همراه با trigger مربوط به animation استفاده کنید.

در فایل template مربوط به HTML، از نام trigger برای اتصال animationهای تعریف‌شده به element موردنظر استفاده کنید.

مرور کد

فایل‌های کد بررسی‌شده در مثال transition در ادامه آمده‌اند.

ts
// #docplaster
import {Component, input} from '@angular/core';
import {trigger, transition, state, animate, style, AnimationEvent} from '@angular/animations';

// #docregion component, events1
@Component({
  selector: 'app-open-close',
  // #docregion trigger-wildcard1, trigger-transition
  animations: [
    trigger('openClose', [
      // #docregion state1
      // ...
      // #enddocregion events1
      state(
        'open',
        style({
          height: '200px',
          opacity: 1,
          backgroundColor: 'yellow',
        }),
      ),
      // #enddocregion state1
      // #docregion state2
      state(
        'closed',
        style({
          height: '100px',
          opacity: 0.8,
          backgroundColor: 'blue',
        }),
      ),
      // #enddocregion state2, trigger-wildcard1
      // #docregion transition1
      transition('open => closed', [animate('1s')]),
      // #enddocregion transition1
      // #docregion transition2
      transition('closed => open', [animate('0.5s')]),
      // #enddocregion transition2, component
      // #docregion trigger-wildcard1
      transition('* => closed', [animate('1s')]),
      transition('* => open', [animate('0.5s')]),
      // #enddocregion trigger-wildcard1
      // #docregion trigger-wildcard2
      transition('open <=> closed', [animate('0.5s')]),
      // #enddocregion trigger-wildcard2
      // #docregion transition4
      transition('* => open', [animate('1s', style({opacity: '*'}))]),
      // #enddocregion transition4
      transition('* => *', [animate('1s')]),
      // #enddocregion trigger-transition
      // #docregion component, trigger-wildcard1, events1
    ]),
  ],
  // #enddocregion trigger-wildcard1
  templateUrl: 'open-close.html',
  styleUrls: ['open-close.css'],
})
// #docregion events
export class OpenClose {
  // #enddocregion events1, events, component
  logging = input(false);
  // #docregion component
  isOpen = true;

  toggle() {
    this.isOpen = !this.isOpen;
  }

  // #enddocregion component
  // #docregion events1, events
  onAnimationEvent(event: AnimationEvent) {
    // #enddocregion events1, events
    if (!this.logging) {
      return;
    }
    // #docregion events
    // openClose is trigger name in this example
    console.warn(`Animation Trigger: ${event.triggerName}`);

    // phaseName is "start" or "done"
    console.warn(`Phase: ${event.phaseName}`);

    // in our example, totalTime is 1000 (number of milliseconds in a second)
    console.warn(`Total time: ${event.totalTime}`);

    // in our example, fromState is either "open" or "closed"
    console.warn(`From: ${event.fromState}`);

    // in our example, toState either "open" or "closed"
    console.warn(`To: ${event.toState}`);

    // the HTML element itself, the button in this case
    console.warn(`Element: ${event.element}`);
    // #docregion events1
  }
  // #docregion component
}
// #enddocregion component
html
<!-- #docplaster -->
<!-- #docregion trigger -->
<nav>
  <button type="button" (click)="toggle()">Toggle Open/Close</button>
</nav>

<div [@openClose]="isOpen ? 'open' : 'closed'" class="open-close-container">
  <p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
</div>
<!-- #enddocregion trigger -->
css
:host {
  display: block;
  margin-top: 1rem;
}

.open-close-container {
  border: 1px solid #dddddd;
  margin-top: 1em;
  padding: 20px 20px 0px 20px;
  color: #000000;
  font-weight: bold;
  font-size: 20px;
}

خلاصه

آموختید با استفاده از style() و state() همراه با animate() برای زمان‌بندی، به transition میان دو state animation اضافه کنید.

در بخش Animation درباره قابلیت‌های پیشرفته‌تر animationهای Angular مطالعه کنید؛ این بخش با تکنیک‌های پیشرفته transitionها و triggerها آغاز می‌شود.

خلاصه API مربوط به Animations

API تابعی ارائه‌شده توسط module با نام @angular/animations یک زبان مخصوص دامنه (DSL) برای ساخت و کنترل animationها در برنامه‌های Angular فراهم می‌کند. برای فهرست کامل و جزئیات syntax توابع اصلی و ساختارهای داده مرتبط، به مرجع API مراجعه کنید.

نام تابععملکرد
trigger()animation را آغاز می‌کند و container تمام فراخوانی‌های دیگر توابع animation است. template مربوط به HTML به triggerName متصل می‌شود. آرگومان اول نام یکتای trigger را تعریف می‌کند. از syntax آرایه استفاده می‌کند.
style()یک یا چند style در CSS را برای استفاده در animation تعریف می‌کند و ظاهر elementهای HTML هنگام animation را کنترل می‌کند. از syntax شیء استفاده می‌کند.
state()مجموعه‌ای نام‌دار از styleهای CSS را ایجاد می‌کند که پس از transition موفق به یک state مشخص اعمال می‌شوند. سپس می‌توان در توابع دیگر animation با نام به آن state ارجاع داد.
animate()اطلاعات زمان‌بندی transition را مشخص می‌کند. مقادیر delay و easing اختیاری‌اند و می‌تواند فراخوانی‌های style() را در خود داشته باشد.
transition()توالی animation میان دو state نام‌دار را تعریف می‌کند. از syntax آرایه استفاده می‌کند.
keyframes()امکان تغییر متوالی میان styleها در یک بازه زمانی مشخص را می‌دهد. درون animate() استفاده می‌شود و می‌تواند در هر keyframe() چند فراخوانی style() داشته باشد.
group()گروهی از مراحل animation ــ animationهای داخلی ــ را برای اجرای موازی مشخص می‌کند. animation تنها پس از تکمیل تمام مراحل داخلی ادامه می‌یابد. درون sequence() یا transition() استفاده می‌شود.
query()یک یا چند element داخلی HTML را درون element فعلی پیدا می‌کند.
sequence()فهرستی از مراحل animation را تعیین می‌کند که به‌ترتیب و یکی‌یکی اجرا می‌شوند.
stagger()زمان شروع animation چند element را با فاصله تنظیم می‌کند.
animation()animation قابل‌استفاده مجددی ایجاد می‌کند که از محل دیگری قابل فراخوانی است. همراه با useAnimation() استفاده می‌شود.
useAnimation()یک animation قابل‌استفاده مجدد را فعال می‌کند. همراه با animation() استفاده می‌شود.
animateChild()اجازه می‌دهد animationهای component فرزند در همان بازه زمانی والد اجرا شوند.

مطالب بیشتر درباره animationهای Angular

ممکن است مطالب زیر نیز برایتان مفید باشند: