阅读时间 10~15min
项目背景
项目中为了优化用户体验加入了几处微交互动画, 过期的流程都是设计输出合成的雪碧图, 前端通过序列帧实现动画效果, 如下图动画效果:
序列帧:
动画效果:
序列帧:
帧动画的缺点和局限性比较明显, 合成的雪碧图文件大, 且在不同屏幕分辨率下可能会失真. 经调研发现, Lottie 是个简单, 高效且性能高的动画方案.
Lottie 是可应用于 Android, iOS, web 和 Windows 的库, 通过 Bodymovin 解析 AE https://www.adobe.com/products/aftereffects.html 动画, 并导出可在移动端和 Web 端渲染动画的 JSON 文件. 换言之, 设计师用 AE 把动画效果做出来, 再用 Bodymovin 导出相应地 JSON 文件给到前端, 前端使用 Lottie 库就可以实现动画效果.
Bodymovin 插件的安装与使用
关闭 AE
下载并安装 ZXP installer
https://aescripts.com/learn/zxp-installer/
下载最新版 bodymovin 插件
把下载好的 bodymovin.zxp 拖到 ZXP installer
打开 AE, 在菜单首选项 -> 常规中勾选: ballot_box_with_check: 允许脚本写入文件和访问网络 (否则输出 JSON 文件时会失败)
在 AE 中制作动画, 打开菜单窗口 -> 拓展 ->Bodymovin, 勾选要输出的动画, 并设置输出文件目录, 点击 render
打开输出目录会看到生成的 JSON 文件, 若动画里导入了外部图片, 则会在 images 中存放 JSON 中引用的图片
前端使用 lottie
静态 URL
- https://cdnjs.com/libraries/lottie-web
- NPM
- NPM install lottie-Web
调用 loadAnimation
- lottie.loadAnimation({
- container: element,
- renderer: 'svg',
- loop: true,
- autoplay: true,
- path: 'data.json'
- });
vue-lottie
也可以在 vue 中使用 lottie
- import lottie from '../lib/lottie';
- import * as favAnmData from '../../raw/fav.json';
- export default {
- props: {
- options: {
- type: Object,
- required: true
- },
- height: Number,
- width: Number,
- },
- data () {
- return {
- style: {
- width: this.width ? `${this.width}px` : '100%',
- height: this.height ? `${this.height}px` : '100%',
- overflow: 'hidden',
- margin: '0 auto'
- }
- }
- },
- mounted () {
- this.anim = lottie.loadAnimation({
- container: this.$refs.lavContainer,
- renderer: 'svg',
- loop: this.options.loop !== false,
- autoplay: this.options.autoplay !== false,
- animationData: favAnmData,
- assetsPath: this.options.assetsPath,
- rendererSettings: this.options.rendererSettings
- }
- );
- this.$emit('animCreated', this.anim)
- }
- }
loadAnimation 参数
container
用于渲染动画的 HTML 元素, 需确保在调用 loadAnimation 时该元素已存在
renderer
渲染器, 可选值为'svg'(默认值)/'canvas'/'html'.svg 支持的功能最多, 但 HTML 的性能更好且支持 3d 图层. 各选项值支持的功能列表在此 https://github.com/airbnb/lottie-web/wiki/Features
loop
默认值为 true. 可传递需要循环的特定次数
autoplay
自动播放
path
JSON 文件路径
animationData
JSON 数据, 与 path 互斥
name
传递该参数后, 可在之后通过 lottie 引用该动画实例
rendererSettings
可传递给 renderer 实例的特定设置, 具体可看
Lottie 动画监听
Lottie 提供了用于监听动画执行情况的事件:
- complete
- loopComplete
- enterFrame
- segmentStart
- config_ready(初始配置完成)
- data_ready(所有动画数据加载完成)
- DOMLoaded(元素已添加到 DOM 节点)
- destroy
可使用 addEventListener 监听事件
- // 动画播放完成触发
- anm.addEventListener('complete', anmLoaded);
- // 当前循环播放完成触发
- anm.addEventListener('loopComplete', anmComplete);
- // 播放一帧动画的时候触发
- anm.addEventListener('enterFrame', enterFrame);
控制动画播放速度和进度
可使用 anm.pause 和 anm.play 暂停和播放动画, 调用 anm.stop 则会停止动画播放并回到动画第一帧的画面.
使用 anm.setSpeed(speed) 可调节动画速度, 而 anm.goToAndStop(value, isFrame) 和 anm.goToAndPlay 可控制播放特定帧数, 也可结合 anm.totalFrames 控制进度百分比, 比如可传 anm.totalFrames - 1 跳到最后一帧.
anm.goToAndStop(anm.totalFrames - 1, 1);
这样的好处是可以把相关联的 JSON 文件合并, 通过 anm.goToAndPlay 控制动画状态的切换, 如下图例中一个 JSON 文件包含了 2 个动画状态的数据:
图片资源
JSON 文件里 assets 设置了对图片的引用:
若想统一修改静态资源路径或者设置成绝对路径, 可在调用 loadAnimation 时传入 assetsPath 参数:
- lottie.loadAnimation({
- container: element,
- renderer: 'svg',
- path: 'data.json',
- assetsPath: 'URL' // 静态资源绝对路径
- });
功能支持列表
即使用 bodymovin 成功输出了 JSON 文件 (没有报错), 也会出现动效不如预期的情况, 比如这是在 AE 中构建的形象图:
但在页面中渲染效果是这样的:
这是因为使用了不支持的 Merge Paths 功能
因此对设计师而言, 创建 Lottie 动画和往常制作 AE 动画有所不同, 此文档 https://airbnb.io/lottie/supported-features.html 记录了 Bodymovin 支持输出的 AE 功能列表, 动画制作前需跟设计师沟通好, 根据动画加载平台来确认可使用的 AE 功能.
尽量遵循官方文档里对设计过程的指导和建议:
动画简单化. 创建动画时需时刻记着保持 JSON 文件的精简, 比如尽可能地绑定父子关系, 在相似的图层上复制相同的关键帧会增加额外的代码, 尽量不使用占用空间最多的路径关键帧动画. 诸如自动跟踪描绘, 颤动之类的技术会使得 JSON 文件变得非常大且耗性能.
建立形状图层. 将 AI,EPS,SVG 和 PDF 等资源转换成形状图层否则无法在 Lottie 中正常使用, 转换好后注意删除该资源以防被导出到 JSON 文件.
设置尺寸. 在 AE 中可设置合成尺寸为任意大小, 但需确保导出时合成尺寸和资源尺寸大小保持一致.
不使用表达式和特效. Lottie 暂不支持.
注意遮罩尺寸. 若使用 alpha 遮罩, 遮照的大小会对性能产生很大的影响. 尽可能地把遮罩尺寸维持到最小.
动画调试. 若输出动画破损, 通过每次导出特定图层来调试出哪些图层出了问题. 然后在 GitHub 中附上该图层文件提交问题, 选择用其他方式重构该图层.
不使用混合模式和亮度蒙版.
不添加图层样式.
全屏动画. 设置比想要支持的最宽屏幕更宽的导出尺寸.
设置空白对象. 若使用空白对象, 需确保勾选可见并设置透明度为 0% 否则不会被导出到 JSON 文件.
预览效果
由于以上所说的功能支持问题会导致输出动画效果不确定性, 设计师和前端之间有个动画效果联调的过程, 为了提高联调效率, 设计师可先进行初步的效果预览, 再把文件交付给前端.
方法 1: 输出预览 HTML 文件
渲染前设置所要渲染的文件
勾选Demo 选项
在输出的文件目录中就可找到可预览的 demo.HTML 文件
方法 2:LottieFiles 分享平台
把生成的 JSON 文件传到 LottieFiles 平台, 可播放, 暂停生成文件的动画效果, 可设置图层颜色, 动画速度, 也可以下载 lottie preview 客户端在 iOS 或 Android 机子上预览.
LottieFiles 平台还提供了很多线上公开的 Lottie 动画效果, 可直接下载 JSON 文件使用
交互 hack
Lottie 的不足之处是没有对应的 API 操纵动画层, 若想做更细化的动画处理, 只能直接操作节点来实现. 比如当播放完左图动画进入惊讶状态后, 若想实现右图随鼠标移动而控制动画层的简单效果:
开启调试面板可以看到, lottie-Web 通过使用标签的 transform 属性来控制动画:
当元素已添加到 DOM 节点, 找到想要控制的标签, 提取其 transform 属性的矩阵值, 并使用 rematrix 解析矩阵值.
- onIntroDone() {
- const Gs = this.refs.svg.querySelectorAll('svg> g> g> g');
- Gs.forEach((node, i) => {
- // 过滤需要修改的节点
- ...
- // 获取 transform 属性值
- const styleArr = node.getAttribute('transform').split(',');
- styleArr[0] = styleArr[0].replace('matrix(', '');
- styleArr[5] = styleArr[5].replace(')', '');
- const style = `matrix(${styleArr[0]}, ${styleArr[1]}, ${styleArr[2]}, ${styleArr[3]}, ${styleArr[4]}, ${styleArr[5]})`;
- // 使用 Rematrix 解析
- const transform = Rematrix.parse(style);
- this.matrices.push({
- node,
- transform,
- prevTransform: transform
- });
- }
- }
监听鼠标移动, 设置新的 transform 属性值.
- onMouseMove = (e) => {
- this.mouseCoords.x = e.clientX || e.pageX;
- this.mouseCoords.y = e.clientY || e.pageY;
- let x = this.mouseCoords.x - (this.props.browser.width / 2);
- let y = this.mouseCoords.y - (this.props.browser.height / 2);
- const diffX = (this.mouseCoords.prevX - x);
- const diffY = (this.mouseCoords.prevY - y);
- this.mouseCoords.prevX = x;
- this.mouseCoords.prevY = y;
- this.matrices.forEach((matrix, i) => {
- let translate = Rematrix.translate(diffX, diffY);
- const product = [matrix.prevTransform, translate].reduce(Rematrix.multiply);
- const CSS = `matrix(${product[0]}, ${product[1]}, ${product[4]}, ${product[5]}, ${product[12]}, ${product[13]})`;
- matrix.prevTransform = product;
- matrix.node.setAttribute('transform', CSS);
- })
- }
进一步优化
看到一个方法, 在 AE 中将图层命名为 **#id 格式, 生成的 SVG 相应的图层 id 会被设置为 id**, 命名为 **.class 格式, 相应的图层 class 会被设置为 class**
试了下的确可以, 如下图, 因此可通过这个方法快速找到需要操作的动画层, 进一步简化代码:
小结
Lottie 的缺点在于若在 AE 动画制作的过程不注意规范, 会导致数据文件大, 耗内存和性能的问题; Lottie-Web 的官方文档不够详尽, 例如 assetsPath 参数是在看源码的时候发现的; 开放的 API 不够齐全, 无法很灵活地控制动画层.
而优点也很明显, Lottie 能帮助提高开发效率, 精简代码, 易于调试和维护; 资源文件小, 输出动画效果保真; 跨平台 --Android, iOS, Web 和 Windows 通用.
总的来说, Lottie 的引用可以替代传统的 GIF 和帧动画, 灵活利用好提供的属性和方法可以控制动画的播放, 但需注意规范设计和开发的流程, 才可以更高效地完成动画的制作与调试.
关注公众号:[IVWEB 社区] , 每周推送精品技术周刊 .
周刊文章集合: https://github.com/feflow/weekly
团队开源项目: Feflow https://github.com/feflow/feflow
来源: https://juejin.im/post/5c8ddddce51d4563ed1efac9