动画
概述
Ionic Animations 是一个工具,使开发者能够以平台无关的方式创建复杂的动画,无需特定框架或 Ionic 应用。
创建高效的动画可能具有挑战性,因为开发者受到可用库和设备硬件资源的限制。此外,许多动画库使用 JavaScript 驱动的方法,这可能会降低动画的可扩展性并消耗 CPU 时间。
另一方面,Ionic Animations 使用 Web Animations API,它将所有动画的计算和运行都移交给浏览器。这种方法允许浏览器优化动画并确保其流畅执行。在不支持 Web Animations 的情况下,Ionic Animations 将回退到 CSS Animations,这在性能上的差异可以忽略不计。
安装
- JavaScript
- TypeScript
- Angular
- Angular (Standalone)
- React
- Vue
使用 Ionic Core 和 JavaScript 的开发者应安装最新版本的 @ionic/core。
import { createAnimation } from 'https://cdn.jsdelivr.net/npm/@ionic/core@latest/dist/esm/index.mjs';
...
const animation = createAnimation()
.addElement(myElementRef)
.duration(1000)
.fromTo('opacity', '1', '0.5');
}
使用 Ionic Core 和 TypeScript 的开发者应安装最新版本的 @ionic/core。
import { createAnimation, Animation } from '@ionic/core';
...
const animation: Animation = createAnimation('')
.addElement(myElementRef)
.duration(1000)
.fromTo('opacity', '1', '0.5');
}
使用 Angular 的开发者应安装最新版本的 @ionic/angular。动画可以通过 AnimationController 依赖注入创建。
import { Animation, AnimationController } from '@ionic/angular';
...
constructor(private animationCtrl: AnimationController) {
const animation: Animation = this.animationCtrl.create()
.addElement(myElementRef)
.duration(1000)
.fromTo('opacity', '1', '0.5');
}
使用 Angular 的开发者应安装最新版本的 @ionic/angular。动画可以通过 AnimationController 依赖注入创建。
import { Animation, AnimationController } from '@ionic/angular/standalone';
...
constructor(private animationCtrl: AnimationController) {
const animation: Animation = this.animationCtrl.create()
.addElement(myElementRef)
.duration(1000)
.fromTo('opacity', '1', '0.5');
}
使用 React 的开发者应安装最新版本的 @ionic/react。React 包装器目前处于 beta 版本。请在 GitHub 上报告任何问题!
import { CreateAnimation, Animation } from '@ionic/react';
...
<CreateAnimation
duration={1000}
fromTo={{
property: 'opacity',
fromValue: '1',
toValue: '0.5'
}}
>
...
</CreateAnimation>
使用 Ionic Vue 的开发者应安装最新版本的 @ionic/vue。
import { createAnimation } from '@ionic/vue';
import { ref } from 'vue';
...
const myElementRef = ref();
...
const animation = createAnimation()
.addElement(myElementRef.value)
.duration(1000)
.fromTo('opacity', '1', '0.5');
}
基本动画
在下面的示例中,创建了一个更改 ion-card 元素的不透明度并将其沿 X 轴从左向右移动的动画。此动画将无限次运行,每次动画迭代持续 1500ms。
默认情况下,所有 Ionic Animations 都处于暂停状态,直到调用 play 方法。
关键帧动画
Ionic Animations 允许你使用关键帧控制动画的中间步骤。这里可以使用任何有效的 CSS 属性,你甚至可以使用 CSS 变量作为值。
在编写关键帧时,连字符分隔的 CSS 属性应使用驼峰式写法。例如,border-radius 应写为 borderRadius。这也适用于 fromTo()、from() 和 to() 方法。
在上面的示例中,卡片元素将从其初始宽度过渡到由 --width 变量定义的宽度,然后过渡到最终宽度。
每个关键帧对象包含一个 offset 属性。offset 是一个介于 0 和 1 之间的值,用于定义关键帧步骤。偏移值必须按升序排列且不能重复。
分组动画
多个元素可以同时进行动画,并通过单个父级动画对象进行控制。除非另有指定,子动画会继承持续时间、缓动和迭代次数等属性。父级动画的 onFinish 回调在所有子动画完成之前不会被调用。
此示例展示了由单个父级动画控制的 3 个子动画。动画 cardA 和 cardB 继承了父级动画的 2000ms 持续时间,但动画 cardC 由于显式设置而具有 5000ms 的持续时间。
Before 和 After 钩子
Ionic Animations 提供了钩子,让你可以在动画运行之前和动画完成之后更改元素。这些钩子可用于执行 DOM 读取和写入,以及添加或删除类和内联样式。
此示例设置了一个内联滤镜,在动画开始前将卡片的背景颜色反转 75%。动画完成后,元素上的 box shadow 被设置为 rgba(255, 0, 50, 0.4) 0px 4px 16px 6px(红色发光),并且内联滤镜被清除。必须停止动画才能移除 box shadow 并再次使用滤镜播放动画。
参见方法了解完整的钩子列表。
链式动画
动画可以链接起来,一个接一个地运行。play 方法返回一个 Promise,在动画完成时解析。
手势动画
Ionic Animations 使开发者能够通过与 Ionic Gestures 无缝集成来创建强大的基于手势的动画。
在以下示例中,我们创建了一个轨道,可以沿其拖动卡片元素。我们的 animation 对象将负责向左或向右移动卡片元素,而我们的 gesture 对象将指示 animation 对象向哪个方向移动。
基于偏好的动画
开发者还可以使用 CSS 变量根据用户偏好(如 prefers-reduced-motion 和 prefers-color-scheme)定制动画。
在首次创建动画时,此方法适用于所有支持的浏览器。大多数浏览器还能够随着 CSS 变量的更改动态更新关键帧动画。
Safari 目前不支持动态更新关键帧动画。对于需要在 Safari 中获得此类支持的开发者,可以使用 MediaQueryList.addListener()。
覆盖 Ionic 组件动画
某些 Ionic 组件允许开发者提供自定义动画。所有动画都作为组件上的属性提供,或通过全局配置设置。
Modals
性能考虑
CSS 和 Web 动画通常在合成线程上处理。这与主线程(布局、绘制、样式和 JavaScript 执行发生的地方)不同。建议优先使用可以在合成线程上处理的属性,以获得最佳的动画性能。
对诸如 height 和 width 等属性进行动画会导致额外的布局和绘制,这可能导致卡顿并降低动画性能。另一方面,对诸如 transform 和 opacity 等属性进行动画可以由浏览器高度优化,通常不会引起太多卡顿。
关于哪些 CSS 属性会导致布局或绘制发生,请参见 CSS Triggers。
调试
有关在 Chrome 中调试动画的信息,有一篇很好的博客文章介绍了如何使用 Chrome DevTools 检查动画:https://developers.google.com/web/tools/chrome-devtools/inspect-styles/animations。
还建议为你的动画分配唯一标识符。这些标识符将显示在 Chrome 的动画检查器中,应该使调试更容易:
/**
* .square 元素的动画应在 Chrome DevTools 中
* 显示 "my-animation-identifier"。
*/
const animation = createAnimation('my-animation-identifier')
.addElement(document.querySelector('.square'))
.duration(1000)
.fromTo('opacity', '1', '0');
API
本节提供了 Animation 类上所有可用方法和属性的列表。
接口
AnimationDirection
type AnimationDirection = 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';
AnimationFill
type AnimationFill = 'auto' | 'none' | 'forwards' | 'backwards' | 'both';
AnimationBuilder
type AnimationBuilder = (baseEl: any, opts?: any) => Animation;
opts 是特定于自定义动画的额外选项。例如,sheet modal 进入动画包含 当前断点的信息。
AnimationCallbackOptions
interface AnimationCallbackOptions {
/**
* 如果为 true,关联的回调将仅触发一次。
*/
oneTimeCallback: boolean;
}
AnimationPlayOptions
interface AnimationPlayOptions {
/**
* 如果为 true,动画将同步播放。
* 这相当于以 0ms 的持续时间运行动画。
*/
sync: boolean;
}
属性
| 名称 | 描述 |
|---|---|
childAnimations: Animation[] | 给定父级动画的所有子动画。 |
elements: HTMLElement[] | 附加到动画的所有元素。 |
parentAnimation?: Animation | 给定动画对象的父级动画。 |
方法
| 名称 | 描述 |
|---|---|
addAnimation(animationToAdd: Animation | Animation[]): Animation | 将一个或多个动画分组在一起,由父级动画控制。 |
addElement(el: Element | Element[] | Node | Node[] | NodeList): Animation | 向动画添加一个或多个元素。 |
afterAddClass(className: string | string[]): Animation | 添加一个类或类数组,在动画结束后添加到动画中的所有元素。 |
afterAddRead(readFn: (): void): Animation | 添加一个执行 DOM 读取的函数,在动画结束后运行。 |
afterAddWrite(writeFn: (): void): Animation | 添加一个执行 DOM 写入的函数,在动画结束后运行。 |
afterClearStyles(propertyNames: string[]): Animation | 添加一个属性名称数组,在动画结束后从动画中所有元素的内联样式中清除。 |
afterRemoveClass(className: string | string[]): Animation | 添加一个类或类数组,在动画结束后从动画中的所有元素中移除。 |
afterStyles(styles: { [property: string]: any }): Animation | 添加一个样式对象,在动画结束后应用于动画中的所有元素。 |
beforeAddClass(className: string | string[]): Animation | 添加一个类或类数组,在动画开始前添加到动画中的所有元素。 |
beforeAddRead(readFn: (): void): Animation | 添加一个执行 DOM 读取的函数,在动画开始前运行。 |
beforeAddWrite(writeFn: (): void): Animation | 添加一个执行 DOM 写入的函数,在动画开始前运行。 |
beforeClearStyles(propertyNames: string[]): Animation | 添加一个属性名称数组,在动画开始前从动画中所有元素的内联样式中清除。 |
beforeRemoveClass(className: string | string[]): Animation | 添加一个类或类数组,在动画开始前从动画中的所有元素中移除。 |
beforeStyles(styles: { [property: string]: any }): Animation | 添加一个样式对象,在动画开始前应用于动画中的所有元素。 |
direction(direction?: AnimationDirection): Animation | 设置动画播放的方向。 |
delay(delay?: number): Animation | 设置动画开始的延迟时间(毫秒)。 |
destroy(clearStyleSheets?: boolean): Animation | 销毁动画并清除所有元素、子动画和关键帧。 |
duration(duration?: number): Animation | 设置动画的持续时间(毫秒)。 |
easing(easing?: string): Animation | 设置动画的缓动效果(毫秒)。参见 Easing Effects 了解可接受的缓动值列表。 |
from(property: string, value: any): Animation | 设置动画的开始样式。 |
fromTo(property: string, fromValue: any, toValue: any): Animation | 设置动画的开始和结束样式。 |
fill(fill?: AnimationFill): Animation | 设置动画在动画执行前后如何将样式应用于其元素。 |
iterations(iterations: number): Animation | 设置在停止之前动画循环应播放的次数。 |
keyframes(keyframes: any[]): Animation | 设置动画的关键帧。 |
onFinish(callback: (didComplete: boolean, animation: Animation): void, opts?: AnimationCallbackOptions): Animation | 添加一个在动画结束时运行的回调。 |
pause(): Animation | 暂停动画。 |
play(opts?: AnimationPlayOptions): Promise<void> | 播放动画。 |
progressEnd(playTo?: 0 | 1, step: number, dur?: number): Animation | 停止在动画中搜索。 |
progressStart(forceLinearEasing?: boolean, step?: number): Animation | 开始在动画中搜索。 |
progressStep(step: number): Animation | 在动画中搜索。 |
stop(): Animation | 停止动画并将所有元素重置为初始状态。 |
to(property: string, value: any): Animation | 设置动画的结束样式。 |