uni.previewImage 不支持平滑缩放动画,因其底层调用系统原生预览组件(iOS QLPreviewController、Android 系统图库、H5 WebView viewer),仅提供基础双指缩放,不暴露 transform 控制权,无法实现缓动、双击、自定义 UI 等效果。

uni.previewImage 本身不支持平滑缩放动画,所谓“平滑缩放”只能靠自己手写组件实现;直接调用 API 只能获得原生级预览(带基础手势,但无缩放过渡、无双击、无自定义 UI)。
为什么 uni.previewImage 没有平滑缩放
uni.previewImage 是封装的原生能力:iOS 调用 QLPreviewController,Android 调用系统图库,H5 调用 WebView 内置 viewer。这些底层组件只提供基础缩放(双指拖拽),不暴露 transform 控制权,也不支持 CSS transition 或 easing 动画。你看到的“丝滑”,其实是系统原生渲染管线做的,不是前端可控的“平滑缩放效果”。
想实现点击放大有缓动、双击缩放带 easing、缩放后拖拽不卡顿——必须放弃 uni.previewImage,改用自绘方案。
用 swiper + movable-view 实现可缩放多图预览
这是目前全端兼容性最好、真机体验最稳的组合。核心是:每张图用一个 swiper-item,内部套 movable-view 做缩放拖拽,swiper 管理左右滑动。
-
swiper设置display-multiple-items="1"(保证单图主导)、current绑定当前索引、监听@change更新状态 - 每个
movable-view开启scale="true",并设scale-min="1"、scale-max="3" - 缩放中心点必须动态计算:
transform-origin不能写死center,得用touchstart时的 clientX/Y 减去图片左上偏移,再除以当前 scale - H5 端要加
touch-action: none阻止浏览器默认缩放干扰;小程序端需在movable-area外层加catchtouchmove防事件冒泡中断 - 缩放后拖拽位移量 =
(e.touches[0].clientX - startX) / currentScale,否则手指移动距离和图片实际位移不匹配
双击缩放如何避免误触和跳变
双击不是简单判断两次 tap,而是靠 touchstart + touchend 的时间差与坐标偏移联合判定:
- 记录第一次
touchstart的timeStamp和clientX/clientY - 第二次
touchend触发时,检查时间差是否< 300ms且两点距离< 25px,否则忽略 - 缩放目标值按当前状态切换:
scale === 1 ? 2.5 : 1,不要硬写固定值 - 缩放前保存当前
transform-origin,缩放后立即重置movable-view的x/y偏移,否则下次拖拽起点错乱 - 用
animation属性触发 CSS transition:transition: transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94)
图片加载失败时怎么兜底
movable-view 里 image 加载失败不会中断整个预览器,但会留白或显示默认占位图。关键是要提前拦截:
- 预览前对每张 URL 调用
uni.getImageInfo({ src }),失败则过滤掉该地址(尤其注意小程序中tempFilePath无法直传) -
image标签加@error="onImgError(index)",出错时替换为本地占位图或隐藏该页 - 避免把
null、undefined、空字符串塞进图片数组,否则swiper渲染异常或白屏 - 安卓真机上大图(>3000px 宽)易 OOM,建议服务端返回带
?x-oss-process=image/resize,w_1200类参数的缩略图 URL
真正难的不是写出来,而是让缩放中心始终落在手指点击位置、让多图滑动和单图缩放互不干扰、让 H5 和小程序 touch 事件行为一致——这些细节没在真机反复调过,光看文档永远踩坑。


















