--- title: "淘宝动效解决方案分享" type: source tags: [mlops, engineering, wechat] source: wechat source_url: "https://mp.weixi" ingested: 2026-05-16 fetcher: wechat-mp-rss sha256: ce461fce4684e44f8ed558e764c2ff4aa667e132dc41d4f6138760121ee3c3a6 sha256: d41b8cb8c7b636d7065cc4239070dcbf16eaaac842490f1cb4f1c4a39f8a9af3 --- --- source: wechat source_url: https://mp.weixin.qq.com/s/IZgKWf3aiJvRE7AaxExi7w ingested: 2026-05-16 feed_name: 大淘宝技术 wechat_mp_fakeid: MP_WXS_3014106999 source_published: 2026-04-15 --- # 淘宝动效解决方案分享 本文提出了一套平台化、协议化、工程化的动效解决方案,覆盖设计(AE插件)、编辑(可视化画布SDK)、布局(align/group动态对齐与成组)、播放(H5/Weex跨端统一Player)、压缩(二进制优化)、代码生成(Lottie→Anime.js)及AI辅助(MCP协议动效Agent)全链路,解决碎片化、多端不一致、性能差、维护难等痛点,实现“一次制作、多端复用、智能可控”。 动效解决方案介绍 在业务迭代中,动效越来越多地承担「表达品牌、引导转化、承载营销玩法」等职责;若工程侧仍停留在「能播动效」这一层,往往在扩展能力、多端一致性、上线质量与长期维护上反复踩坑。下面归纳我们在实践中反复遇到的问题,并说明为何要走向平台化、协议化、工程化的动效解决方案。 1\. 标准 Lottie 很好,但业务上常缺以下几类扩展能力,例如: * 布局与结构:响应式布局、动态元素居中、动态元素成组等在运行时可动态调整; * 动态内容:资源快速替换、局部热更新而非整段重播、按接口/状态驱动某一图层或切片; * 降级与容错:图层级别、资源级别的降级策略(例如关动效保主流程),避免复杂动画拖垮页面或引发崩溃; * 可编排与可检索:元数据、查询标签、命名规范,方便业务按规则检索片段驱动动画; 2\. 碎片化方案的中长期成本过高 各业务线对于动效的能力要求不一,采用的播放器种类繁多,有专属于业务的定制诉求,不方便复用;而且在某些场景会各自采用hack实现,短期能上线,长期可能会加大维护成本;动效这种跨团队、跨端的共性能力,适合沉淀为平台级供给。 3.「能导出」不等于「能上线」 从 AE 到线上,中间缺的是:检测与优化、可视化编辑、动态替换与布局、降级与监控、多端一致播放。缺一环可能会在联调与线上事故里补票。 4\. 当播放器在Weex与H5的能力不对等时,业务无法共用一套动效资产 当两端播放器能力不一致(如API、扩展协议、降级策略、替换能力不同)时,会出现同一需求采用多套动效资源、多套方案播放的情况, 平台侧无法承诺「一次制作,多端复用」。我们希望 H5 / Weex 采用同套 API 与扩展协议,同套资源同套代码能多端复用。 5\. 体积与性能是持续压力 例如动效文件压缩与解析(动效体积、图片/矢量资源是否可进一步优化和压缩)、文件渲染性能(帧率、首帧时间、内存峰值)等,属于全链路问题,单靠某一端的临时优化很难根治。 6\. 易被忽略但会放大成本的内容 资产版本管理、与发布的衔接;可校验的设计—研发约定,如图层命名、占位符约定、切片语义,需要可校验的规范,减少口头对齐;部分场景的无障碍(动效开关、降级策略等)。 为此,我们提供了以下的动效解决方案,用一条清晰的交付主链路,把「设计产出 → 可配置资产 → 运行时播放」都串联在了一起;同时在中间层用扩展协议来承载占位、切片、降级、编组、布局等策略,避免把业务规则硬编码进播放器或散落各处。 1. 对设计师来说,仍在 AE 里主创作,交付方式升级为链接 + 平台能力;预览、标注、体积与兼容性提示前移,减少「设计以为能播、上线发现不能播」的返工; 2. 对开发者来说,在编辑器里完成二次编辑与业务配置,提供动效扩展能力,不必手写DOM hack;统一播放器 API 屏蔽多端差异,配合错误类型与降级资源,接入更方便; 3. 对业务与平台来说,一套链路覆盖生产、交付、运行与治理,便于规模化复用与质量保障。 技术点分析 ## ## ▐ ** ** AE插件研发 在研发AE(After Effects)插件的过程中,我们沉淀了插件在插件开发、插件热更新、插件日志、读取AE数据、插件构建、构建打包、版本推送方面的全流程能力。基于 CEP(Chromium Embedded Framework) 的 AE 扩展:面板是 Web 技术栈(React),与 AE 本体通过 ExtendScript / JSX 交换工程数据;对Bodymovin 进行了二次开发与交付。 通过此插件我们打通了AE软件与动效平台的直接连接,设计师可通过此插件提前查看动效还原度、进行动效检测与优化,同时直接在动效平台完成动效交付。此插件提供了以下的能力: * 提前进行扫码预览,保证还原度 * 图片资源编辑与一键优化 * 提前进行资源检测、体积检测、兼容性检测 * 与动效平台集成,直接交付动效 * 可以查看并交付动效参数 设计师无需手动导出文件、预览文件、交付文件、上传文件,只需要分享项目空间给到研发同学即可。 ## ## ## ▐ ** ** 动效可视化编辑 动效编辑器赋予开发者与设计师更多的灵活性,能对导入的动效进行细致的调整,而不只是简单的使用已经做好的动效。在中间动画播放器对应的画布中直接拖动到动画对应的某帧,选择动画中的元素,调整位置、尺寸、属性, 或者为其添加占位符、定义降级策略等等。 在浏览器里编辑动画,本质上是两件事叠在一起: 1. 渲染层:把动画变成可看见的 SVG(以及与之对齐的坐标系); 2. 编辑层:在「看起来像画布」的区域里,让用户像在设计工具里一样点选、拖动、改尺寸,并把操作可靠地写回动画数据中。 本项目的做法是:渲染仍走Lottie动效的 SVG 渲染,但在图层创建时注入「可编辑标识」与「交互事件」;React 页面负责容器、选中态、叠加 UI 与历史记录。 这样避免用一套完全自研的渲染器重做 Lottie,又能在图层的粒度上做选中与变换。 预处理过程为每个可编辑图层生成稳定唯一标识,在 SVG 图层根节点上同时挂上: * 作为 DOM ` id ` (便于 ` getElementById ` 精确定位) * 作为数据属性(便于与侧栏、列表里同一图层对齐) * 可选的样式类名(区分「画布上的 SVG 」与其它 UI) 渲染器在创建图层容器时,若该图层带有上述身份,则注册到「当前画布上所有可交互图层 id 列表」,并立即挂上交互。这样选中与变换的入口始终是「用户点中的那个 SVG 组」,而不是再做一次几何拾取去猜 JSON 里的第几个图层。 用户点击图层时,通过事件总线向外壳抛出 「某图层被选中」 事件,外壳(编辑器)监听该信号后,把当前选中图层 id 存进 React 状态,驱动后续 UI。 若每次鼠标移动都深拷贝并改写整份 JSON,会卡顿且难以做惯性、节流。因此交互上采用经典策略: * 拖动中:只改当前 SVG 节点上的 二维变换(例如 ` transform ` 矩阵),保证流畅度; * 拖动结束:计算相对空间的总位移,通过统一 变换动作交给数据层,按规则写回 JSON;有动画则按关键帧结构批量偏移等。 画布显示比例不是 1:1 时,位移总量要除以编辑器缩放系数,才能得到实际的偏移长度单位。 缩放过程中同样先改矩阵与内部位图尺寸相关属性,实时向面板派发缩放系数等;结束时发出 resize 类动作,由数据层更新 JSON 中缩放与资源展示相关字段。 为保证「看动画」与「改动画」“不打架”,用事件总线区分模式: * 进入播放:若存在选中,先清理选中样式;并移除所有已注册图层的指针交互(避免动画播放时误拖); * 暂停:重新为各图层加回交互,恢复编辑能力; * 进入矢量顶点编辑:临时移除常规图层交互(避免与顶点拖拽冲突),退出时再恢复暂停下的编辑能力。 这是一个简单的状态机,保证同一时刻只有一种状态: 选中后,需要在画布上画选框、控制点、辅助线,若放在 React 树顶层用绝对定位计算,容易与 SVG 变换、滚动、缩放错位。 我们的思路是,用 Portal 把叠加组件挂到「当前选中图层根节点」内部。这样叠加图形与图层内容天然同一 SVG 坐标系,只需按图层的几何信息(如宽高、路径顶点)生成子 ` g ` 与 ` path ` 、 ` circle ` 就行。 * 普通选中框:例如针对可缩放的图片层,根据图层矩形生成描边与控制点(具体展示策略由数据类型决定); * 矢量顶点模式:从 JSON 读出路径顶点,在相同 ` g ` 下渲染可拖顶点,拖动时用交互库更新顶点坐标,松手后写回 shape 数据。 最后修改完成后,内核通过事件向上抛出动作(移动、缩放、进入/退出顶点编辑等)。外壳监听后: 1. 调用更新工具(内部通过 id 映射找到图层或资源) 2. 更新应用状态中的当前 JSON 文件 3. 触发重新加载视图,使画布与数据一致 历史记录(撤销栈)在动作已落成新 JSON 时追加,保证一步操作对应一份可还原快照。 另一条通道是外部直接改 JSON(如撤销、批量替换):通过同一事件总线通知播放器替换数据,保持内核与外壳一致。 核心的几点考虑整理如下: 描述 | 设计要点 ---|--- 身份绑定 | JSON 图层稳定 id → SVG 根节点 id + 数据标记,作为一切交互与回写的锚点 选中 | 点击上行事件 + 外壳状态;可选 DOM 类名同步侧栏 变换 | 拖动/缩放先改 SVG,结束再写 JSON;位移用缩放系数还原设计单位 叠加 UI | Portal 进选中图层,共享坐标系,减少换算误差 模式 | 播放与编辑互斥;顶点编辑再互斥一层 桥接 | 全局对象挂载事件总线、当前帧、缩放系数、选中 id 属性面板 | 高频过程可命令式写表单,降低重渲染压力 我们将其抽离为了动效的可交互式画布SDK,可以让你的动效编辑起来更简单。 ## ▐ ** ** 动效内容布局约束 居中对齐(align)和成组布局(group)是用于处理动画中动态内容替换后布局调整常用到的功能。当业务通过 ` replaceData ` 替换文本或图片内容时,这些元素的宽度可能发生变化,导致原始布局错乱。居中对齐功能确保一组元素在容器内保持整体居中,而成组布局功能则确保同组元素根据对齐方式自动调整相对位置,维持视觉一致性。 * 动画居中对齐 例如中间的金额数字是动态传入的文案,这里文案的长度不固定,比如无论是“15.99元”或者是“100元”,都希望能整体居中对齐。 之前业务针对这类的需求,会采用hack方式去实现:让设计师给到图层id,研发去查询指定的DOM,并重写innerHTML,非常简单粗暴。我们希望在编辑器内能配置占位符元素的居中,包括单个占位符的整体居中、多个占位符组合后的整体居中。不管在播放器中占位符传入多长的文本,都能自动调整其位置。 1. 编辑器:能配置【N个占位符】的对齐模式 2. 播放器:需要识别【N个占位符】的对齐模式 单元素处理逻辑如下: parentOffset = 父链上 sum(p - a)(若有)若存在 parent:  p.x = parentOffset - pageW/2 - anchor.x   // 与「父级 + 锚点」关系推导否则:  p.x = pageW/2 + anchor 多元素(N ≥ 2)对应的通用范式: 先将图层按 ` axis ` 排序,再算原始左右边距 ` minL ` 、 ` maxR ` (相对 ` pageW ` ),再用 replaceData 得到新宽度 ` newW[ ] ` ,更新 ` minL ` / ` maxR ` 。 保持相邻间距(文案变宽时不是简单整体平移):对首尾元素施加 ` remainGapOffset1/2 ` ,中间元素在 N>2 时尽量不动,由首尾吸收宽度差。通用范式可描述为: 组合居中的条件:计算中轴:      c1 = p1 - a1      c2 = p2 - a2计算整体居中的位移 alignCenterOffset      minL = c1 - w1/2  minL = c1 - new1/2      maxR = lottieW - (c2 + w2/2)  maxR = lottieW - (c2 + newW2/2)      alignCenterOffset = (maxR - minL) / 2计算保持间距不变的位移      addW = (newW1 + newW2) - (w1 + w2)      remainGapOffset = addW / 4计算父节点的位移      parentOffset = parentP1 - parentA1计算p:      p1 = p1 - remainGapOffset + alignCenterOffset - parentOffset      p2 = p2 + remainGapOffset + alignCenterOffset - parentOffset扩展到N个元素的通用范式:p1 += -remainGapOffset1 + alignCenterOffset - parentOffset(第一个元素)p2 += alignCenterOffset - parentOffset(中间元素)p3 += alignCenterOffset - parentOffset(中间元素)p4 += remainGapOffset2 + alignCenterOffset - parentOffset(最后一个元素) 整体流程如下 : 1. 一维轴上排序 2. 每元素半宽得到包围盒左右界 3. 替换内容后更新宽度并重算包围盒 4. 用「首尾补偿」保持间距不变 5. 整体平移使包络在 ` pageW ` 内居中 6. 叠加父级/预合成偏移 * 动画成组布局 例如在动画的播放过程中,数字“160”是动态传入的,数字的长度不固定,那么后面的“积分抽”、“20”、“次”都要左右进行适当的偏移,才能与前面的数字保持相同的间距。 例如最前方的文案可能是“获得”,也可能是“今天续卡再送”,中间的数字也是不固定的,后面的文案也是不固定的,那完全可以将这些元素采用成组的方式,来保证元素间的间距始终一致。 ` group ` 不负责把一组东西摆到屏幕中央,而是:在同一组占位符里,只关心「左侧谁变宽了」,按文本对齐方式决定当前层要额外平移多少,避免右侧被左侧替换后的文字盖住或留白异常。 对当前元素 ` groupItem ` : 1. ` currentInitPosition = getInitPosition(当前层) ` (首关键帧或静态) 2. ` leftItems ` = 同组内满足: ` ty === TEXT ` 且 ` replaceData[item] ` 有值且初始位置在当前左侧的项 3. 对每个 ` leftItem ` : * * widthDiff = newWidth(leftItem) - oldWidth(leftItem)offsetX += widthDiff * justifyFactor(justify) 对齐因子(与 AE 文本 ` justify ` 一致):左对齐1、右对齐0、居中0.5、两端0。 4\. 返回 ` offsetX ` ,写到当前层的位置参数 N 元素成组时的通用范式: 设组内从左到右为 ` E_0, …, E_{N-1} ` ,仅部分有替换数据。对第 k 个元素: * offset(k) = Σ_{i 交付 -> 编辑 -> 播放 -> 验收 -> 上线 -> 监控”逐步走向真正的无感化与智能化。例如,在生产阶段,AI可以辅助设计生成动效方案、补全关键帧、优化节奏和参数配置;在交付阶段,可以自动完成资源转换、规范检查和多端适配;在编辑阶段,可以通过语言降低任何形式动效类型的调参与修改门槛;在播放阶段,可以结合端能力与运行环境进行动态策略选择和性能优化;在验收阶段,可以基于视觉对比、交互回放和规则识别自动发现问题;在上线和监控阶段,则可以持续追踪播放成功率、卡顿指标、资源异常、版本回退等关键数据。 团队介绍 本文作者冷卉,来自淘天集团-跨端技术团队。本团队服务于淘宝基础用户产品,是淘宝重要的业务线之一。团队以前端、Weex、Native端的技术解决方案框架和研发模式不断完善自己,持续探索端智能等创新,打造极致的体验和工程技术,保障多端设备的适配和稳定运行,致力于让亿级规模的交付能够更丝滑、更稳定。 # ** ¤ ** ** 拓展阅读 ** ** ¤ ** [ 3DXR技术 ]() | [ 终端技术 ]() | [ 音视频技术 ]() [ 服务端技术 ]() | [ 技术质量 ]() | [ 数据算法 ]()