uni-app不支持原生共享元素动画,需手动模拟:h5用getboundingclientrect+transform实现,app(nvue)用animation模块,小程序仅能伪共享(截图+cover-image动画)。

uni-app 页面跳转时怎么启用共享元素动画
uni-app 原生不支持类似 Android Shared Element 或 iOS UIViewControllerTransitioningDelegate 那样的声明式共享元素动画。所谓「共享元素动效」在 uni-app 中必须手动模拟,核心思路是:两个页面中用相同 id(或 ref)标记元素,跳转前捕获位置/尺寸,跳转后在目标页复原并驱动过渡。
实际能走通的路径只有两条:一是用 uni.navigateTo + animation API 手动做位移缩放;二是借助 uni-app 的 web-view 或自定义组件 + transform + transition 在 web 平台实现近似效果。App 和小程序平台限制极多,基本不可行。
- App 端:
nvue支持animation模块,但跨页面无法直接访问另一页面的节点,需通过全局状态或事件总线传递坐标 - H5 端:可用
getBoundingClientRect()+transform+transition实现较连贯的缩放平移动画 - 微信小程序:不支持跨页面 DOM 操作,且
animation无法作用于其他页面的节点,只能退化为「伪共享」——比如跳转前截图、跳转后在新页用绝对定位+缩放还原该图
为什么 uni-app 的 animation 在页面跳转后失效
因为 animation 是运行时绑定到当前页面节点的,跳转后原页面实例被销毁,所有未完成的动画直接中断。这不是 bug,而是生命周期决定的必然行为。
常见错误现象:uni.createAnimation 创建后调用 export(),再用 uni.navigateTo,结果动画只闪一下就没了——这是因为动画执行依赖当前页面的渲染上下文,而新页面没有继承旧页面的动画状态。
- 正确做法:动画必须在目标页面内启动,起始状态由上一页传入(如通过
url参数或uni.$emit传递boundingClientRect数据) - 参数差异:
uni.createAnimation的duration和timingFunction必须与 CSS 的transition匹配,否则视觉脱节 - 兼容性影响:H5 可用
transform: scale() translate();App(nvue)需用animation.translateX等原生方法;小程序只能靠scale+left/top绝对定位硬凑
如何安全传递共享元素的位置和尺寸数据
不能直接传 DOM 节点或 rect 对象(序列化失败),必须提取关键数值并校准坐标系。尤其要注意不同平台的单位差异:H5 是 px,小程序是 rpx,App(nvue)是 px 但可能受屏幕密度影响。
实操建议:统一转成相对于视口左上角的像素值,并在目标页根据 uni.getSystemInfoSync().screenWidth 做归一化处理。
- 捕获阶段:在源页面调用
uni.createSelectorQuery().select('#share-el').boundingClientRect(),拿到{ left, top, width, height } - 传递方式:用
uni.navigateTo({ url: '/pages/detail/detail?left=100&top=200&width=80&height=80' }),避免对象深传 - 还原阶段:目标页
onLoad中解析参数,用uni.createAnimation或style动态设置初始位置,再触发动画 - 容易踩的坑:未考虑滚动偏移(
window.scrollY),导致top值不准;或未等目标页view渲染完成就执行动画(需用nextTick或setTimeout微调)
小程序里「伪共享动画」怎么写才不卡顿
微信小程序不支持跨页面操作节点,唯一可行方案是:源页截图 → 跳转 → 目标页用 cover-image 或 image 显示该图 → 动画缩放平移 → 动画结束隐藏图片,露出真实内容。
性能关键点在于截图时机和图片加载。用 canvas 截图耗时高,推荐用 uni.canvasToTempFilePath + uni.hideTabBar 提前准备;但更轻量的做法是用 uni.createSelectorQuery 获取 rect 后,直接用一个 image 标签覆盖在目标页顶部,靠 transition 驱动。
- 示例片段:
<image :src="tempImg" class="shared-cover" :style="{ transform: `translate(${tx}px, ${ty}px) scale(${scale})` }"></image>,其中tx/ty/scale由传入参数计算得出 - 必须加
mode="aspectFill"防止拉伸变形;class="shared-cover"需设position: fixed; z-index: 999; - 动画结束后立即
this.tempImg = '',否则内存泄漏;iOS 小程序对transform动画帧率敏感,duration不宜超过 300ms
top 值不是相对视口,而是相对父容器,不手动减去 scrollTop 就会飘移。











