uni.previewImage 黑屏或报错主因是传参格式错误,仅接受扁平字符串数组如['url1','url2'],需校验每项为非空字符串;H5需CORS支持,APP需相册权限;不支持缩放入场动画,索引须用Array.indexOf精确获取,组件销毁时须守卫回调防止内存泄漏。

uni.previewImage 为什么点开是黑屏或报错?
直接调用 uni.previewImage 却看不到图,大概率是传参格式不对。它不接受纯 URL 数组以外的结构——哪怕你加了个 url 字段包装,也会静默失败。
常见错误写法:{ url: 'https://xxx.jpg' } 或 [{ path: 'https://xxx.jpg' }];正确只接受扁平字符串数组:['https://xxx.jpg', 'https://yyy.png']。
- 预览前务必先校验每项是否为有效非空字符串,
typeof item === 'string' && item.trim() - H5 端需确保图片支持跨域(
CORS头),否则白屏无提示;小程序端不受此限 - APP 端若使用自定义基座,要确认是否禁用了相册权限,否则调起即失败(错误码
1002)
如何让预览从当前点击位置“放缩入场”?
uni-app 原生 uni.previewImage 不支持自定义动画起点,所谓“缩放入场”实际是伪需求——它本身就是一个全屏原生视图,没有 DOM 层级和过渡控制权。
真要实现视觉上的“从缩略图放大到全屏”,必须放弃 uni.previewImage,改用自定义 modal + u-popup 或 uni-popup 搭配 u-image 的 show-menu-by-longpress 和手势缩放能力。
- 关键点:点击时记录缩略图
boundingClientRect,在 popup 打开后用transform: scale()+transition模拟入场动效 - 注意安卓 WebView 对
scale+position: fixed的渲染兼容性差,建议 fallback 到淡入 - 手势缩放需额外引入
@dcloudio/uni-ui的uni-gesture-pinch,或自己监听touchmove计算双指距离
封装组件里怎么同步当前预览索引?
当你在组件内用 v-for 渲染多张图,并希望点击某张后预览时默认定位到它,不能依赖 current 参数“猜”——因为 uni.previewImage 的 current 只认数组下标,且要求该下标对应 URL 必须和 urls 数组完全一致(不能有空格、编码差异)。
典型坑:urls = ['a.jpg', 'b.jpg'],但你传 current: 'a.jpg'(字符串而非数字)或 current: 0.5,都会 fallback 到第一张。
- 安全做法:点击时用
Array.indexOf()显式获取下标,再传给current - 如果
imageList是对象数组(如{ url: 'x.jpg', id: 123 }),请预先提取出纯 URL 数组缓存,避免每次预览都map - 微信小程序中,
current若超出urls.length,会自动取模,但 H5 和 APP 端直接报错或卡死
预览时如何避免内存泄漏或重复注册事件?
在组件 onUnload 或 beforeUnmount 阶段没清理预览相关状态,下次进入页面可能触发上一次残留的 previewImage 回调,尤其配合 vuex 或 pinia 全局状态时更明显。
最常被忽略的是:预览过程本身无法被 JS 中断,但你的组件销毁了,回调函数却还挂着——比如你在 onSuccess 里写了 this.$nextTick 或 setTimeout,而此时组件实例已失活。
- 所有异步回调(包括
uni.previewImage的success/fail)都要加if (!this._isMounted) return守卫 - 不要在预览回调里直接修改
data响应式数据,改用nextTick包一层,或改用ref+onBeforeUnmount手动置空 - 如果用了
uni.addPhoneContact类扩展 API 触发预览,记得在onHide里调用uni.removePhoneContact清理监听器
实际预览逻辑往往卡在“以为能控制,其实不能”的认知偏差上。真正需要的不是花哨动效,而是 URL 格式干净、索引准确、生命周期守得住——剩下的交给平台原生能力就好。











