找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2066

积分

0

好友

276

主题
发表于 昨天 16:36 | 查看: 2| 回复: 0

在日常开发中,一些复杂的动画交互效果单纯通过 CSS 来实现往往力不从心。常见的替代方案是使用 GIF 动图,但当动画复杂且对清晰度、流畅度有较高要求时,GIF 的大体积又成了影响用户体验的新瓶颈。

这时,Lottie 动画库便是一个优雅的解决方案。它允许开发者直接加载由 UI 设计师导出的 .json 文件,从而在项目中实现高效、高清且高度可控的复杂动画效果。

本文将以 uniapp 的微信小程序 为例,采用微信小程序官方推荐的 lottie-miniprogram 库进行实践介绍。我们将深入核心流程,探讨实际开发中可能遇到的各种“坑”,并最终将这些经验沉淀为一个可直接复用的 Vue 3 组件。如果你也在寻找一种超越传统 CSS 和 GIF 的动画实现方式,这篇文章或许能为你提供清晰的路径。

开发环境

  • Node: 20.13.1
  • NPM: 10.5.2

主要依赖包

包名 版本
@dcloudio/uni-app 3.0.0-4030620241128001
vue 3.4.21
lottie-miniprogram 1.0.12

二、核心实现流程

1. 安装依赖

第一步是通过 npm 安装核心库。

npm install --save lottie-miniprogram

2. 绑定 Canvas 组件

Lottie 在小程序中的渲染依赖于 <canvas> 组件。你需要在页面的模板中声明它,并为其指定一个唯一的 idtype="2d"

<canvas id="lottieCanvas" type="2d"></canvas>

随后,在组件的 <script setup> 中,你需要获取这个 canvas 节点的引用,并将其“安装”给 Lottie。

import lottie from "lottie-miniprogram";
import { getCurrentInstance, onMounted } from "vue";

onMounted(() => {
  uni
    .createSelectorQuery()
    .in(getCurrentInstance().proxy)
    .select("#lottieCanvas")
    .node((res) => {
      const canvas = res.node;
      lottie.setup(canvas);
      // 后续加载动画的代码...
    })
    .exec();
});

3. 调用 Lottie 接口加载动画

在成功获取并设置 canvas 后,就可以调用 lottie.loadAnimation 来加载并播放动画了。你可以选择直接传入 JSON 对象 (animationData) 或一个远程 JSON 文件的 URL (path)。

lottie.setup(canvas);
state.animation = lottie.loadAnimation({
  loop: true,
  autoplay: true,
  rendererSettings: {
    context: canvas.getContext("2d"),
  },
  animationData: ..., // 或 path: ...
});

重要提示:当页面或组件卸载时,务必手动销毁动画实例以释放资源。

state.animation.destroy();

lottie-miniprogram 官方说明摘要:

  • 基于 lottie-web 封装,可根据需要切换底层版本。
  • 依赖微信小程序基础库 2.9.0 及以上版本正式开放的 type="2d" canvas。
  • 不支持 AE 动画中的 expression 表达式(因为小程序安全策略禁止动态执行 JS)。

三、常见问题分析与解决方案

理论流程看似简单,但实践中总会遇到一些棘手的问题。下面是我们总结的几个典型“坑”及其应对策略。

1. 动画比例不对 / 图像模糊

问题现象:设计师提供的动画尺寸是像素(px)单位,而小程序开发使用的是响应式单位(rpx)。同时,如果不处理设备像素比(DPR),在高清屏上 Canvas 绘制的内容会显得模糊。

根本原因

  1. px 与 rpx 的单位转换问题。
  2. Canvas 的绘图上下文未根据 DPR 进行缩放。

解决方案

  • 在设置 Canvas 节点的 widthheight 属性时,将设计稿的 rpx 值转换为实际的物理像素(px)。
  • 同时,通过 canvas.getContext(“2d”).scale(dpr, dpr) 放大绘图上下文,确保绘制指令在高分辨率设备上生效。

2. CSS 修改 Canvas 位置无效

问题现象:尝试使用 margin, position 等 CSS 属性调整 canvas 位置,但发现完全不起作用。

根本原因:在小程序中,<canvas> 属于原生组件,其层级始终高于 WebView 渲染的普通视图组件,因此不受普通 CSS 样式的影响。

解决方案

  • 放弃使用 CSS 定位,改为在初始化时通过 JavaScript API (uni.createSelectorQuery) 获取节点信息并计算其位置。
  • 更常见的做法是,将 canvas 放置在一个通过 CSS 定位的容器 view 中,然后让 canvas 充满该容器,通过控制容器的位置来间接控制 canvas。

3. 动画 JSON 文件部分效果不生效

问题现象:有些从 After Effects (AE) 导出的 .json 文件,在 AE 或 LottieFiles 预览网站上显示正常,但放入小程序后,渐变、某些特效或图层丢失了。

猜测原因

  • AE 中使用的某些特性或插件效果,Lottie 官方库尚未完全支持。
  • 导出 .json 时的 Bodymovin 插件配置或 AE 版本可能导致兼容性问题。

应对建议

  • 先在 Lottie 官方预览器json.cn 的 Lottie 预览工具 中测试 JSON 文件,确认其通用兼容性。
  • 与设计师沟通,检查动画中是否使用了 Lottie 不支持的特性(如复杂的表达式、特定的插件效果),并尝试简化动画。

四、组件封装:LottieAnimation

为了提升开发效率,避免在每个页面重复处理上述问题,我们将最佳实践封装成一个可复用的 Vue 3 组件

✅ 组件设计目标

  • 开箱即用:传入宽高(支持 rpx)、动画数据即可显示。
  • 清晰显示:自动处理 rpx 转 px 和 DPR 缩放,解决模糊问题。
  • 灵活数据源:支持传入本地 JSON 对象或远程 JSON 文件 URL。
  • 可控生命周期:支持通过 isShow 控制显示/隐藏,自动管理动画的创建与销毁。

🌟 组件完整代码 (uni-app + Vue3 + TypeScript)

以下是 components/LottieAnimation/LottieAnimation.vue 的完整实现。

<!-- components/LottieAnimation/LottieAnimation.vue -->
<template>
  <div
    v-if="props.isShow"
    class="lottie-container"
    :style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }"
  >
    <canvas
      id="lottieCanvas"
      type="2d"
      :style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }"
    ></canvas>
  </div>
</template>

<script setup lang="ts">
import lottie from "lottie-miniprogram";
import { getCurrentInstance, onMounted, onUnmounted, reactive } from "vue";

const props = withDefaults(defineProps<{
  isShow: boolean;
  json: Record<string, any> | string;
  width: number;
  height: number;
}>(), {});

const state = reactive({
  animation: null as ReturnType<typeof lottie.loadAnimation> | null,
});

const actions = {
  rpxToPx(rpx: number) {
    return (rpx / 750) * uni.getWindowInfo().windowWidth;
  },
};

onMounted(() => {
  const instance = getCurrentInstance();
  if (!instance) return;

  uni
    .createSelectorQuery()
    .in(instance.proxy)
    .select("#lottieCanvas")
    .node((res) => {
      const canvas = res.node;
      const ctx = canvas.getContext("2d");
      const dpr = uni.getSystemInfoSync().pixelRatio;

      // 关键步骤:设置Canvas实际宽高并缩放上下文
      canvas.width = actions.rpxToPx(props.width) * dpr;
      canvas.height = actions.rpxToPx(props.height) * dpr;
      ctx.scale(dpr, dpr);

      const options = {
        loop: true,
        autoplay: true,
        rendererSettings: { context: ctx },
      };

      // 支持传入对象或URL字符串
      if (typeof props.json === "string") {
        options.path = props.json;
      } else {
        options.animationData = props.json;
      }

      lottie.setup(canvas);
      state.animation = lottie.loadAnimation(options);
    })
    .exec(() => {
      state.animation?.play();
    });
});

onUnmounted(() => {
  state.animation?.destroy();
});
</script>

<style>
.lottie-container {
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

五、在页面中使用组件

封装完成后,在页面中的使用方式变得非常简单直观。

<template>
  <div class="container">
    <LottieAnimation :isShow="true" :json="data" :width="200" :height="200" />
  </div>
</template>

<script setup lang="ts">
import LottieAnimation from "@/components/LottieAnimation/LottieAnimation.vue";
// 假设你有一个本地的JSON动画文件
import data from "@/components/LottieAnimation/json/data.json";
</script>

<style>
.container {
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #f5f5f5;
  box-sizing: border-box;
  padding-bottom: 200rpx;
}
</style>

六、扩展资源与参考

本文涉及的完整示例代码可在代码仓库中查看。

总结

通过上述步骤,我们不仅掌握了在 uniapp 微信小程序 中集成 Lottie 动画的核心技术,还系统性地解决了清晰度、布局兼容性等常见问题,并将这些解决方案封装成了高质量的复用组件。这种从问题出发,以实践为导向,最终沉淀为可复用资产的过程,正是高效前端开发的精髓。希望这份实践总结能为你的项目带来便利,也欢迎在 云栈社区 与其他开发者继续探讨更多前端技术与工程实践。




上一篇:前端开发高频考点与疑难解析:从渐进增强到性能优化的70-102问
下一篇:Vue3插槽(Slot)核心用法与进阶组件开发技巧
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-7 05:34 , Processed in 0.606548 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表