赞
踩
在海外项目中,为了优化用户体验加入了几处微交互动画,实现方式是设计输出合成的雪碧图,前端通过序列帧实现动画效果:
序列帧:
动画效果:
序列帧:
帧动画的缺点和局限性比较明显,合成的雪碧图文件大,且在不同屏幕分辨率下可能会失真。经调研发现,Lottie是个简单、高效且性能高的动画方案。
Lottie是可应用于Android, iOS, Web和Windows的库,通过Bodymovin解析AE动画,并导出可在移动端和web端渲染动画的json文件。换言之,设计师用AE把动画效果做出来,再用Bodymovin导出相应地json文件给到前端,前端使用Lottie库就可以实现动画效果。
NPM
npm install lottie-web
调用 loadAnimation
- lottie.loadAnimation({
- container: element, // 容器节点
- renderer: 'svg',
- loop: true,
- autoplay: true,
- path: 'data.json' // JSON文件路径
- });
也可以在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)
- }
- }
container | 用于渲染动画的HTML元素,需确保在调用loadAnimation时该元素已存在 |
renderer | 渲染器,可选值为'svg'(默认值)/'canvas'/'html'。svg支持的功能最多,但html的性能更好且支持3d图层。各选项值支持的功能列表在此 |
loop | 默认值为true。可传递需要循环的特定次数 |
autoplay | 自动播放 |
path | JSON文件路径 |
animationData | JSON数据,与path互斥 |
name | 传递该参数后,可在之后通过lottie命令引用该动画实例 |
rendererSettings | 可传递给renderer实例的特定设置,具体可看 |
Lottie提供了用于监听动画执行情况的事件:
可使用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动画有所不同,此文档记录了Bodymovin支持输出的AE功能列表,动画制作前需跟设计师沟通好,根据动画加载平台来确认可使用的AE功能。
除此之外,尽量遵循官方文档里对设计过程的指导和建议:
由于以上所说的功能支持问题会导致输出动画效果不确定性,设计师和前端之间有个动画效果联调的过程,为了提高联调效率,设计师可先进行初步的效果预览,再把文件交付给前端。
渲染前设置所要渲染的文件
勾选☑️Demo选项
在输出的文件目录中就可找到可预览的demo.html文件
把生成的JSON文件传到LottieFiles平台,可播放、暂停生成文件的动画效果,可设置图层颜色、动画速度,也可以下载lottie preview客户端在iOS或Android机子上预览。
LottieFiles平台还提供了很多线上公开的Lottie动画效果,可直接下载JSON文件使用
Lottie的不足之处是没有对应的API操纵动画层,若想做更细化的动画处理,只能直接操作节点来实现。比如当播放完左图动画进入惊讶状态后,若想实现右图随鼠标移动而控制动画层的简单效果:
开启调试面板可以看到,lottie-web通过使用<g>标签的transform属性来控制动画:
当元素已添加到DOM节点,找到想要控制的<g>标签,提取其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
试了下的确可以,如下图,因此可通过这个方法快速找到需要操作的动画层,进一步简化代码:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。