angular-animations

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

@angular/animations

@angular/animations

Version: Angular 21 (2025) Tags: Animations, UI, Transitions, Motion
References: Animations GuideAPInpm
版本: Angular 21 (2025) 标签: Animations, UI, Transitions, Motion
参考: 动画指南APInpm

API Changes

API变更

This section documents recent version-specific API changes.
  • NEW: Modern animation API — Use
    animateEnter
    and
    animateLeave
    over deprecated
    :enter
    /
    :leave
  • NEW: CSS-based animations — Angular team recommends CSS for better performance
  • NEW: View transitions API — Support for browser View Transitions API
  • DEPRECATED:
    :enter
    and
    :leave
    — Use
    animateEnter
    and
    animateLeave
    instead
本部分记录了近期对应版本的API变动。
  • 新增:现代化动画API — 推荐使用
    animateEnter
    animateLeave
    替代已弃用的
    :enter
    /
    :leave
  • 新增:基于CSS的动画 — Angular团队推荐使用CSS实现以获得更优性能
  • 新增:视图过渡API — 支持浏览器原生View Transitions API
  • 已弃用:
    :enter
    :leave
    — 请使用
    animateEnter
    animateLeave
    替代

Best Practices

最佳实践

  • Enable animations module
ts
import { provideAnimations } from '@angular/platform-browser/animations';

export const appConfig: ApplicationConfig = {
  providers: [
    provideAnimations()
  ]
};
  • Use triggers for state-based animations
ts
import { trigger, state, style, transition, animate } from '@angular/animations';

@Component({
  animations: [
    trigger('fadeInOut', [
      state('hidden', style({ opacity: 0 })),
      state('visible', style({ opacity: 1 })),
      transition('hidden <=> visible', animate(500))
    ])
  ]
})
export class FadeComponent {
  isVisible = signal(false);
}
  • Use enter/leave animations
ts
@Component({
  animations: [
    trigger('slideIn', [
      transition(':enter', [
        style({ transform: 'translateX(-100%)' }),
        animate('300ms ease-in', style({ transform: 'translateX(0%)' }))
      ]),
      transition(':leave', [
        animate('300ms ease-out', style({ transform: 'translateX(-100%)' }))
      ])
    ])
  ]
})
export class SlideComponent {}
  • Use wildcard states for any transition
ts
trigger('expand', [
  transition('* => expanded', [
    style({ height: '*' }),
    animate('300ms ease-out', style({ height: '200px' }))
  ]),
  transition('expanded => *', [
    animate('300ms ease-in', style({ height: '*' }))
  ])
])
  • Use query and stagger for list animations
ts
trigger('listAnimation', [
  transition('* => *', [
    query(':enter', [
      style({ opacity: 0 }),
      stagger(100, [
        animate('300ms', style({ opacity: 1 }))
      ])
    ], { optional: true })
  ])
])
  • Use animation callbacks
ts
@Component({
  template: `
    <div [@fade]="state" 
         (@fade.start)="onAnimationStart()"
         (@fade.done)="onAnimationDone()">
    </div>
  `
})
export class AnimComponent {
  onAnimationStart() { console.log('Start'); }
  onAnimationDone() { console.log('Done'); }
}
  • Use reusable triggers
ts
// animations.ts
export const fadeAnimation = trigger('fade', [
  transition(':enter', [
    style({ opacity: 0 }),
    animate('300ms', style({ opacity: 1 }))
  ]),
  transition(':leave', [
    animate('300ms', style({ opacity: 0 }))
  ])
]);
  • Use functional animations (Angular 17+)
ts
@Component({
  animations: [
    trigger('expanded', [
      transition(':expanded', [
        animate('300ms cubic-bezier(0.4, 0, 0.2, 1)')
      ])
    ])
  ]
})
export class ExpandComponent {}
  • Optimize for performance
ts
// Prefer transform and opacity
transition('* => *', [
  animate('200ms', style({ 
    transform: 'translateX(10px)',
    opacity: 0.5 
  }))
])

// Avoid expensive properties
// ❌ Don't animate: width, height, margin, top
// ✅ Do animate: transform, opacity
  • Provide reduced motion for accessibility
ts
@Component({
  animations: [
    trigger('slide', [
      transition('* => *', [
        style({ '@.disabled': '' }), // Disable for reduced motion
        animate('300ms')
      ])
    ])
  ]
})
  • 启用动画模块
ts
import { provideAnimations } from '@angular/platform-browser/animations';

export const appConfig: ApplicationConfig = {
  providers: [
    provideAnimations()
  ]
};
  • 为基于状态的动画使用触发器
ts
import { trigger, state, style, transition, animate } from '@angular/animations';

@Component({
  animations: [
    trigger('fadeInOut', [
      state('hidden', style({ opacity: 0 })),
      state('visible', style({ opacity: 1 })),
      transition('hidden <=> visible', animate(500))
    ])
  ]
})
export class FadeComponent {
  isVisible = signal(false);
}
  • 使用进入/离开动画
ts
@Component({
  animations: [
    trigger('slideIn', [
      transition(':enter', [
        style({ transform: 'translateX(-100%)' }),
        animate('300ms ease-in', style({ transform: 'translateX(0%)' }))
      ]),
      transition(':leave', [
        animate('300ms ease-out', style({ transform: 'translateX(-100%)' }))
      ])
    ])
  ]
})
export class SlideComponent {}
  • 为任意过渡使用通配符状态
ts
trigger('expand', [
  transition('* => expanded', [
    style({ height: '*' }),
    animate('300ms ease-out', style({ height: '200px' }))
  ]),
  transition('expanded => *', [
    animate('300ms ease-in', style({ height: '*' }))
  ])
])
  • 为列表动画使用query和stagger
ts
trigger('listAnimation', [
  transition('* => *', [
    query(':enter', [
      style({ opacity: 0 }),
      stagger(100, [
        animate('300ms', style({ opacity: 1 }))
      ])
    ], { optional: true })
  ])
])
  • 使用动画回调
ts
@Component({
  template: `
    <div [@fade]="state" 
         (@fade.start)="onAnimationStart()"
         (@fade.done)="onAnimationDone()">
    </div>
  `
})
export class AnimComponent {
  onAnimationStart() { console.log('Start'); }
  onAnimationDone() { console.log('Done'); }
}
  • 使用可复用触发器
ts
// animations.ts
export const fadeAnimation = trigger('fade', [
  transition(':enter', [
    style({ opacity: 0 }),
    animate('300ms', style({ opacity: 1 }))
  ]),
  transition(':leave', [
    animate('300ms', style({ opacity: 0 }))
  ])
]);
  • 使用函数式动画(Angular 17+)
ts
@Component({
  animations: [
    trigger('expanded', [
      transition(':expanded', [
        animate('300ms cubic-bezier(0.4, 0, 0.2, 1)')
      ])
    ])
  ]
})
export class ExpandComponent {}
  • 性能优化
ts
// 优先使用transform和opacity
transition('* => *', [
  animate('200ms', style({ 
    transform: 'translateX(10px)',
    opacity: 0.5 
  }))
])

// 避免高开销属性
// ❌ 不要做动画的属性:width, height, margin, top
// ✅ 推荐做动画的属性:transform, opacity
  • 为无障碍需求提供减弱动效支持
ts
@Component({
  animations: [
    trigger('slide', [
      transition('* => *', [
        style({ '@.disabled': '' }), // 为减弱动效场景禁用动画
        animate('300ms')
      ])
    ])
  ]
})