|
前言之前做运营活动的时候,写了一个比较有趣的打开盲盒的交互动画,流程如下:一个「挣扎的」未打开的盲盒,点击出现确认弹窗,确认后集齐的5张卡片会「飞入」盲盒,盲盒「开启」弹出礼品。怎么实现的呢?其中「挣扎的效果」是使用的CSS3做的一个呼吸加抖动的Animation,「飞入的效果」是使用JS获取到盲盒的中心点坐标并设置弹窗只展示5张卡片和要改变的样式,「盲盒开启的过程」则是一个Lottie动画。如果想要在页面中实现类似的动效,那大概有以下几个方案可以选用:CSS3动画:使用CSS3新增的属性和选择器来实现动画,也是最常见的前端动画方案优点是实现简单,不需要太多的代码也可以实现较为复杂的动画效果缺点是不可控。比较适用于对于元素做一些形变、位移、透明度变化等,比如:按钮呼吸,文本淡出等JavaScript动画:通过JavaScript脚本来实现动画效果优点是非常灵活,可以交互,渲染动态数据等,可以配合CSS3做一些动画流程,比如开红包等缺点是实现较为复杂,需要编写大量的代码,动画质量受限于开发水平GIF/APNG图片:通过引入动图来实现动画效果,APNG相较于GIF支持更多的色彩,性能稍好优点是没什么开发成本缺点是循环播放动画不可控,存在较大的性能问题。适合做小图标,比如:loading加载Lottie:本文的主角优点是开发成本较低,可以实现复杂的动画效果,动画可控,性能较好缺点在需要一个很会的UI设计,动画中动态渲染数据较为麻烦前端做动画还存在许多方案例如:Canvas、SVG、SVGA等,这里不做过多介绍大家可以自行了解什么是Lottie「Lottie」是Airbnb开发的一款开源的动画库,它可以把AdobeAfterEffects制作的动画导出为交互式的矢量动画,可以在iOS、Android和ReactNative等移动平台上使用。它通过解析用「Bodymovin」导出为「json」的AE动画,在移动端和Web上进行了原生渲染。能够帮助开发者快速制作出精美的动画效果,而且还可以节省大量的开发时间。Lottie如何使用第一步由动画设计同学使用AE实现动画效果后通过「Bodymovin」插件导出json文件或者在「Lottie」动画资源网站如:Lottiefiles找到现成的动画进行编辑后导出。对于「Bodymovin」插件的安装与使用可以参考该文章:AE插件Bodymovin介绍(见参考资料4)在实现动画时要考虑各端对于AE效果的支持,具体可参考官方文档(见参考资料1)第二步开发同学安装「Lottie」,根据设计同学提供的json文件在项目中使用安装lottie-web依赖,在项目中进行引用npm install lottie-web# 或使用pnpmpnpm add lottie-webimport bodymovin from 'lottie-web'通过以下几种方式初始化「Lottie」并挂载到页面中使用「Lottie」的loadAnimation方法进行配置,其中挂载节点container和json文件路径path这两个是必须配置的 使用「Lottie」的registerAnimation方法进行注册,挂载节点以入参形式传入,json文件路径需在节点中配置data-animation-path属性 使用searchAnimations方法进行注册,「Lottie」自行通过document.querySelector选择类名为“lottie”的节点进行挂载,json文件路径需在节点中添加data-animation-path属性 另外「Lottie」实例也提供了许多的Method和Event,可以控制动画播放、暂停、卸载等。更多API请移步官方文档看懂JSON文件其实json文件就是对于导出动画的具象描述基本信息{ "v": "5.7.1", // Bodymovin 插件版本号 "fr": 25, // 帧率 "ip": 0, // 开始帧 "op": 20, // 结束帧 "w": 700, // 宽 "h": 600, // 高 "nm": "测试文件", // 名称 "ddd": 0, // 是否为3D "assets": [], // 静态资源 "layers": [], // 图层信息 "markers": [] // 标记}其中包括了一些基本信息:插件版本、画布的宽高、帧率、起始关键帧,结束帧等。从中我们不难看出这个测试动画1000/25*20=800播放一次时长为800毫秒,宽高比为7:6assets静态资源{ "assets": [ { "id": "image_0", // 唯一标识 "w": 169, // 宽 "h": 172, // 高 "u": "images/", // 静态资源导出文件夹 "p": "img_0.png", // 文件路径 "e": 0 // 是否直接使用p作为路径 } ]}这里是制作动画时引用到的静态资源,使用时通过唯一标识“id”进行指定关于获取静态资源的路径,遵从以下逻辑:e不为0 时直接以p作为路径e为0时,如果初始化时配置了assetsPath则使用其与p进行拼接,若没配置则使用u进行拼接作为路径function getAssetsPath(assetData, assetsPath, originalPath) { var path = ''; if (assetData.e) { path = assetData.p; } else if (assetsPath) { path = assetsPath + assetData.p; } else { path = originalPath; path += assetData.u ? assetData.u : ''; path += assetData.p; } return path;}layers图层{ "layers": [ { "ddd": 0, // 是否使用了3d "ind": 1, // 索引 "ty": 2, // 图片图层 "nm": "图层2.png", // 名称 "cl": "png", // 图片后缀 "refId": "image_0", // 在assets中的id "sr": 1, "ks": { // 需要做的变化 "o": {}, // 不透明度 "r": {}, // 旋转 "p": {}, // 位置 "a": {}, // 锚点 "s": {} // 缩放 }, "ao": 0, // 自动 "ip": 4, // 开始帧 "op": 18, // 持续帧 "st": 0, // 开始时间 "bm": 0 // 混合模式 } ]}各个图层相关的信息,其中包括了对应元素的「ORPAS」变换,即为透明,旋转,位置,锚点、缩放每一个变化的对象内部又包括了:起止时间,贝塞尔曲线的入参等描述源码解析以registerAnimation方法为例,看看「Lottie」的工作流程吧function registerAnimation(element, animationData) { if (!element) { // 没传入挂载DOM直接结束 return null; } var i = 0; // 缓存注册的动画 while (i 当使用SVGRender进行渲染时,观察DOM结构发现对于元素的变化都是使用CSS函数「matrix」进行描述的总的来说使用「matrix」函数可以代替transform的以下属性:斜拉(skew)、缩放(scale)、旋转(rotate)、位移(translate),这些方法都是基于「matrix」函数的再封装,为了易于理解更为详细的了解可以参考这篇博客(见参考资料3)requestAnimationFramefunction resume(nowTime) { var elapsedTime = nowTime - initTime; // 时间戳差值 var i; for (i = 0; i
|
|