小程序中使用 lottie 动画 | 踩坑经验分享

lottie · 浏览次数 : 11

小编点评

**问题** 在小程序中使用 lottie 动画时,出现以下问题: * **expression 表达式报错信息**:由于 expression 特性是不支持的,需要禁用相关特性才能导出 JSON 文件。 * **模糊问题**:由于动画文件尺寸不确定,设置 canvas 宽高会有模糊问题。 * **文字替换问题**:需要在添加一个文字时将 ${num} 进行替换,但该字符串可能包含 ${num} 的格式,导致问题。 **解决方案** **1. 禁用 expression 特性** 在导出 JSON 文件之前,禁用 expression 特性,使其不可用。这可以通过将 `animationData.expressions` 设置为 `null` 来实现。 ```javascript const animationData = JSON.parse(jsonText.replace('${金额}', '目标金额')); animationData.expressions = null; ``` **2. 调整 canvas 宽高** 在设置 canvas宽高之前,需要获取设备的窗口宽高。这可以通过调用 `wx.getSystemInfoSync()` 函数获取,然后将它们设置为 canvas 的宽高。 ```javascript const canvas = res[0].nodecanvas.width = windowWidth * pixelRatiocanvas.height = windowHeight * pixelRatio; ``` **3. 处理文字替换问题** 在添加文字时,将 ${num} 替换为一个固定格式的文本,例如 `${num} 元`。确保该文本和动画中的文本具有相同的字体。 **4. 解决 iOS 播放闪退问题** 在使用 `wx:if` 控制元素时,确保动画已完全播放完毕。这可以通过检查 `animation.status` 属性来实现。 **完整代码** ```javascript // ... // 获取设备的信息 const { windowWidth, windowHeight, pixelRatio } = wx.getSystemInfoSync() // 设置 canvas 宽高 canvas.width = windowWidth * pixelRatiocanvas.height = windowHeight * pixelRatio; // 导出 JSON 文件 const jsonData = await new Promise((resolve) => { wx.request({ url: 'http://127.0.0.1:8080/json/text-replace/data.json', success: (res) => { resolve(res.data); } }); }); // 处理 expression 特性 const animationData = JSON.parse(jsonText.replace('${金额}', '目标金额')); animationData.expressions = null; // 加载动画 const ani = lottie.loadAnimation({ animationData, assetsPath: 'http://127.0.0.1:8080/json/text-replace/images/', }); // 监听动画完成事件 ani.addEventListener('complete', () => { console.log('动画播放结束'); }); // 设置元素可见 wx:if ("{{show}}""> const canvas = res[0].nodecanvas; canvas.style.display = 'block'; canvas.style.width = `${windowWidth * pixelRatio}px`; canvas.style.height = `${windowHeight * pixelRatio}px`; lottie.setup(canvas); ```

正文

最近被拉去支援紧急需求(赶在五一节假日前上线的,双休需要加班😱),参与到项目中才知道,开发的项目是微信小程序技术栈的。由于是临时支援,笔者也很久没开发过微信小程序了,所以挑选了相对独立,业务属性相对轻薄的模块参与。

其中有个营销活动(领红包🧧😁)的弹窗动画就要用到 lottie 动画。

本文就分享一下在小程序中使用 lottie 过程中遇到的问题与解决办法。

关于 lottie

lottie 是 Airbnb 开源的一个动画库,用于在端上直接播放 AE ( Adobe After Effects)动画。

通过 bodymovin AE 插件将动画文件导出为 json 文件,lottie SDK 通过可以通过 JSON 文件直接播放动画。

具体 demos 效果可以上 LottieFiles 网站查看。

如何使用 AE 导出动画需要的JSON文件

完成 AE 软件安装后,参照 Lottie Web GitHub 官方文档 完成 bodymovin 插件的安装。

打开动画文件后,只需简单几步操作

① window 中选择 Bodymovie

② 选择需要导出的动画资源

③ 导出配置(小程序相关)

点击对应动画的设置

勾选 Glyphs 将用到的文字+字体导出为图形。

小程序里渲染不支持加载外部字体。

这个就会有 tree shake的效果,如果动画里没有用到的文字,做动态替换的时候就会不显示,后面会详细介绍到

勾选 Convert expressions to keyframes 将表达式转为关键帧,因为小程序里不支持使用 eval 等动态执行脚本的能力。

修改完成后点击Save保存配置。

④ 渲染导出 JSON 文件

最后点击 Render 按钮,导出 JSON 文件。

导出文件如下,data.json 文件就是我们需要的 JSON 文件,images 里存储的就是播放要用到的图片文件。

小程序中使用

可以使用小程序官方封装的 lottie-miniprogram 库。

快速验证的话可以打开微信开发者工具,在点击👉🏻 demo代码片段 进行创建。

① 安装依赖

npm install --save lottie-miniprogram

② 使用

tip:开发者工具中验证的话,渲染模式需要选择 webview ,Skyline 目前还不支持调试 canvas

index.wxml

<canvas id="lottie-canvas" type="2d"></canvas>

index.js

import lottie from 'lottie-miniprogram'

Page({
  onReady() {
    this.createSelectorQuery().select('#lottie-canvas').node((res) => {
      // 取得 canvas 节点
      const canvas = res[0].node

      // 设置 cavnas 画布尺寸
      canvas.width = 600
      canvas.height = 600

      lottie.setup(canvas)

      const context = canvas.getContext('2d')
      const lottieInstance = lottie.loadAnimation({
        loop: true, // 循环播放
        autoplay: true, // 自动播放
        // 本地使用 http-server 启动服务后,指定本地资源地址
        path: 'http://127.0.0.1:8080/lottie-demo-sources/data.json', // 通过http 制定json资源路径

        // 也可以用下面这种方式,直接传入 lottie json内容
        // (需要动态替换文案就需要用到这种方式)
        // animationData: {/* lottie json 格式内容 */},
        // 静态资源目录,通常与 animationData 配合使用
        // assetsPath: 'http://127.0.0.1:8080/lottie-demo-sources/images/',

        rendererSettings: {
          context,
        },
      })
    }).exec()
  }
})

我这个 demo 的效果(网上找的动画素材)如下。

问题&解决

下面介绍在实际业务接入使用中遇到的一些问题和解决办法。

expression 表达式

报错信息如下,这是遇到的第一个问题(也是上面导出配置中有特别说明的)。

细看了一下文档,有特别说明,expression 表达式特性是不支持的,因此需要再导出 JSON 文件时禁用相关特性。

解决办法:导出JSON文件时,禁用掉表达式特性即可。

当然禁用后,JSON 文件大小会有所增加。

比如我这个 demo 从 40kb 增加到了 240kb(当然动画不一样,增长的大小会有所不同。有些前后可能只有1-2kb的变化)。

模糊

由于需要全屏展示,动画文件的尺寸不确定,手动只设置 canvas 尺寸会有模糊的问题。

这个通过掘金搜索了一下就得到了 lottie动画模糊问题的解决方法

微调一下上面的代码,就可以解决模糊问题。

const canvas = res[0].node
canvas.width = 600
canvas.height = 600

// 下面是新增的代码
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = canvas.width * dpr
canvas.height = canvas.height * dpr
context.scale(dpr, dpr)

lottie.setup(canvas)

全屏动画

弹窗的动画需要全屏展示,因此需要设置 canvas 宽高为页面宽高。

index.wxss

#lottie-canvas{
    position: fixed;
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
}

index.js,使用 wx.getSystemInfoSync 获取设备的信息

const { windowWidth, windowHeight, pixelRatio } = wx.getSystemInfoSync()
canvas.width = windowWidth * pixelRatio
canvas.height = windowHeight * pixelRatio

动态文案

由于是红包,需要动态展示金额(当然也可能是不固定内容的动态标题)。

思路可以参考这篇文章知乎: 动态修改 Lottie 中的文本

可以使用固定格式的文本 ${文本} 进行替换

// 伪代码
get('sourceUrl').then((res) => {
  const jsonText = res.data
  const animationData = JSON.parse(jsonText.replace('${金额}', '目标金额'))
})

比如我在 demo 里加一个文字

  • 需要展示的文本里放入 ${num} 用于替换匹配
  • 在添加一个文本藏在看不见的地方,里面写入替换后需要用到的文字(确保和上面的文本为同一种字体)

接着导出 JSON 文件。

调用方法如下

// 拉取JSON文件内容
const jsonData = await new Promise((resolve) => {
  wx.request({
    url: 'http://127.0.0.1:8080/json/text-replace/data.json',
    success: (res) => {
      resolve(res.data)
    }
  })
})

// 随机生成1-100元的数字,保留两位小数
const num = (Math.random() * 100).toFixed(2)
// 替换内容
const animationData = JSON.parse(
  JSON.stringify(jsonData)
    .replace(/\$\{num\}/g, `${num}元`)
)

lottie.loadAnimation({
  // 指定json内容
  animationData,
  // 设置依赖的图片资源位置
  assetsPath: 'http://127.0.0.1:8080/json/text-replace/images/',
  // ...省略其它配置
})

效果如下

style 引发的渲染错误

在 canvas 标签上设置 display控制显隐,偶现会提示渲染层错误。

<canvas style="display:{{show?'block':'none'}}" id="c1" type="2d"></canvas>

解决办法,给套了一层 view,用wx:if控制咯。

<view  wx:if="{{show}}">
  <canvas id="c1" type="2d"></canvas>
</view>

iOS 播放闪退问题

现象是,非冷启动小程序的时候,动画还没播放完毕就提前结束了。

看代码log,3s的动画,播放不到 1s 就触发了 complete 事件,看现象就是一闪而逝。

const ani = lottie.loadAnimation({
  // 3s 的动画
  animationData,
  // ...省略其它配置
})

ani.addEventListener('complete', () => {
  console.log('动画播放结束')
})

解决办法

TODO:未完待续

最后

时间匆忙,介绍的不是非常的详细,感兴趣的同学可以评论区交流。

demo 完整源码见 GitHub:lottie-demo

与小程序中使用 lottie 动画 | 踩坑经验分享相似的内容:

小程序中使用 lottie 动画 | 踩坑经验分享

最近被拉去支援紧急需求(赶在五一节假日前上线的,双休需要加班),参与到项目中才知道,开发的项目是微信小程序技术栈的。由于是临时支援,笔者也很久没开发过微信小程序了,所以挑选了相对独立,业务属性相对轻薄的模块参与。 其中有个营销活动(领红包)的弹窗动画就要用到 lottie 动画。 本文就

低功耗引擎 Cliptrix 有什么价值

在一些硬件配置较低的设备(如 POS 机,穿戴设备等)中运行使用小程序时可能会出现无法运行,运行后卡顿的问题。 Cliptrix 的开发目标则是作为完全独立的小程序渲染引擎,与当前小程序逻辑分开,最终完全替换现有的 WebView 引用,保证即使在硬件配置较低的设备中也可以提供流畅的使用与运行体验。

Go函数介绍与一等公民

Go函数介绍与一等公民 函数对应的英文单词是 Function,Function 这个单词原本是功能、职责的意思。编程语言使用 Function 这个单词,表示将一个大问题分解后而形成的、若干具有特定功能或职责的小任务,可以说十分贴切。函数代表的小任务可以在一个程序中被多次使用,甚至可以在不同程序中

【炫丽】从0开始做一个WPF+Blazor对话小程序

大家好,我是沙漠尽头的狼。 .NET是免费,跨平台,开源,用于构建所有应用的开发人员平台。 本文演示如何在WPF中使用Blazor开发漂亮的UI,为客户端开发注入新活力。 注 要使WPF支持Blazor,.NET版本必须是 6.0 或更高版本,本文所有示例使用的.NET 7.0,版本要求见链接,截图

当你使用Taro时,你需要了解的一些事儿

2017 年 1 月 9 日凌晨,万众期待的微信小程序正式上线,前有跳一跳等爆圈小游戏的带动,后有特殊时期下各类健康码小程序的加持,小程序成为了国内技术圈独树一帜的存在。但随着小程序的迅猛发展,其实在小程序发展的过程中,关于小程序的架构就层出不穷,小程序架构的后面也会绑定一个专属 DSL,如类 React 或者类 Vue。

微信小程序使用微信云托管添加自定义域名并转发到pexels.com

背景:我要在小程序上显示pexels.com上的图片,然后我得先把pexels.com的域名添加到小程序的request合法域名中,但是pexels.com是国外的,在国内没有备案所以添加不了。解决方案就是:用一个已经备案好的域名进行转发,转发的服务器我选择的是微信云托管,备案好的域名还需要ssl,

使用taro+canvas实现微信小程序的图片分享功能

业务场景 二轮充电业务中,用户充电完成后在订单详情页展示订单相关信息,用户点击分享按钮唤起微信小程序分享菜单,将生成的图片海报分享给微信好友或者下载到本地,好友可通过扫描海报中的二维码加群领取优惠。 使用场景及功能:微信小程序 生成海报图片 分享好友 下载图片 使用技术:Taro vue vant

FinClip 小程序的自有账户体系是怎么做的?

随着公司规模越来越大,员工需要使用的产品矩阵也会越来越丰富,不仅包括内部的 IT 系统,OA 系统,业务系统,还会有很多和外部产品集成的登录流程,更别提各种业务系统或者子系统中的账户体系了。如果使用简单粗暴的方法,让员工在每一个系统中单独注册一个独立的账户,不仅员工的用户体验简单粗暴,也会陡然提升员工密码管理的相关成本。

路由react-router-dom的使用

react-router-dom路由简介 现代的前端页面大多是SPA(单页面应用程序), 也就是只有一个HTML页面的程序,这样用户体验好,服务器压力小,所以更受欢迎。路由是使用单页面来管理原来多页面的功能。 路由的功能:从一个页面,跳转到另一个页面。 在React中,路由是一套映射规则,是URL路

桌面应用打包:pyinstaller

在使用python开发一些小工具时,如果其他人电脑中没有python环境或者没有安装相应的第三方库,是没办法运行的,而要求对方安装又不现实,尤其是对方不是技术人员,因此如何将一个独立的python程序,使它成为成为一个不用考虑环境,双击即可运行的桌面应用呢?使用pyinstaller打包是一个不错的选择。