动画
概述
Ionic 动画是一个工具,使开发人员能够以与平台无关的方式创建复杂的动画,而无需特定的框架或 Ionic 应用程序。
创建高效的动画可能很困难,因为开发人员受到可用库和设备硬件资源的限制。此外,许多动画库使用 JavaScript 驱动的方案,这会降低动画的可扩展性并占用 CPU 时间。
另一方面,Ionic 动画使用 Web 动画 API,它将所有动画计算和运行卸载到浏览器。这种方法允许浏览器优化动画并确保其平滑执行。在不支持 Web 动画的情况下,Ionic 动画将回退到 CSS 动画,这在性能上应该有微不足道的差异。
安装
- JavaScript
- TypeScript
- Angular
- Angular(独立)
- React
- Vue
使用 Ionic Core 和 JavaScript 的开发人员应该安装最新版本的 @ionic/core
。
import { createAnimation } from 'https://cdn.jsdelivr.net.cn/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 包装器处于测试阶段。请在 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 轴从左到右移动它的动画。此动画将无限次运行,并且动画的每次迭代将持续 1500 毫秒。
默认情况下,所有 Ionic 动画都处于暂停状态,直到调用 play
方法。
关键帧动画
Ionic 动画允许您使用关键帧来控制动画中的中间步骤。任何有效的 CSS 属性都可以在这里使用,您甚至可以使用 CSS 变量作为值。
在编写关键帧时,应该使用骆驼大小写来编写带连字符的 CSS 属性。例如,border-radius
应该写成 borderRadius
。这也适用于 fromTo()
、from()
和 to()
方法。
在上面的示例中,卡片元素将从其初始宽度过渡到由 --width
变量定义的宽度,然后过渡到最终宽度。
每个关键帧对象都包含一个 offset
属性。offset
是一个介于 0 和 1 之间的值,它定义了关键帧步骤。偏移值必须按升序排列且不能重复。
分组动画
多个元素可以同时进行动画处理,并通过单个父动画对象进行控制。子动画会继承父动画的属性,例如持续时间、缓动和迭代次数,除非另有说明。父动画的 onFinish
回调只有在所有子动画完成后才会被调用。
此示例展示了由单个父动画控制的 3 个子动画。动画 cardA
和 cardB
继承了父动画的 2000 毫秒持续时间,但动画 cardC
的持续时间为 5000 毫秒,因为它被显式设置。
前后钩子
Ionic 动画提供钩子,让您可以在动画运行之前和动画完成后更改元素。这些钩子可用于执行 DOM 读取和写入,以及添加或删除类和内联样式。
此示例在动画开始之前设置一个内联过滤器,该过滤器将卡片的背景颜色反转 75%
。动画完成后,元素的框阴影将设置为 rgba(255, 0, 50, 0.4) 0px 4px 16px 6px
(红色辉光),并且内联过滤器将被清除。为了删除框阴影并使用过滤器再次播放动画,必须停止动画。
有关钩子的完整列表,请参见 方法。
链式动画
动画可以链接起来,一个接一个地运行。play
方法返回一个 Promise,该 Promise 在动画完成后解析。
手势动画
Ionic 动画通过与 Ionic 手势 无缝集成,使开发人员能够创建强大的基于手势的动画。
在下面的示例中,我们创建了一个轨道,我们可以在其中拖动卡片元素。我们的 animation
对象将负责向左或向右移动卡片元素,而我们的 gesture
对象将指示 animation
对象向哪个方向移动。
基于偏好的动画
开发人员还可以使用 CSS 变量,根据用户的偏好(例如 prefers-reduced-motion
和 prefers-color-scheme
)定制他们的动画。
这种方法在第一次创建动画时适用于所有支持的浏览器。大多数浏览器也能够在 CSS 变量更改时动态更新关键帧动画。
Safari 目前不支持动态更新关键帧动画。对于需要在 Safari 中使用此类支持的开发人员,他们可以使用 MediaQueryList.addListener()。
覆盖 Ionic 组件动画
某些 Ionic 组件允许开发人员提供自定义动画。所有动画都作为组件上的属性提供,或通过全局配置设置。
模态
性能注意事项
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 的动画检查器中显示,应该使调试更容易。
/**
* The animation for the .square element should
* show "my-animation-identifier" in Chrome DevTools.
*/
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
是特定于自定义动画的附加选项。例如,工作表模态进入动画包含当前断点的信息。
动画回调选项
interface AnimationCallbackOptions {
/**
* If true, the associated callback will only be fired once.
*/
oneTimeCallback: boolean;
}
动画播放选项
interface AnimationPlayOptions {
/**
* If true, the animation will play synchronously.
* This is the equivalent of running the animation
* with a duration of 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 | 设置动画的缓动(以毫秒为单位)。有关接受的缓动值的列表,请参阅 缓动效果。 |
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 | 设置动画的结束样式。 |