uni.previewImage需路径归一化:H5用URL.createObjectURL()转blob,小程序/App直传tempFilePaths;多图用flex+calc模拟grid;删图用splice并设唯一key;上传须分步或直传,禁用filter和formData塞数组。

uni.previewImage 传参必须是完整可访问路径,不能直接传 tempFilePaths
点开图片黑屏或报错 previewImage:fail invalid data,90% 是因为把 uni.chooseImage 返回的 tempFilePaths 数组直接塞进了 uni.previewImage({ urls: ... })。H5 端的 tempFilePath 是 blob: 协议,小程序和 App 虽能识别本地临时路径,但 H5 完全不认。
正确做法是:预览前先做路径归一化处理——
- App 和小程序:直接用
tempFilePaths,无需转换 - H5:必须用
URL.createObjectURL(file)生成https://或blob:可读地址(注意:仅限预览,不可上传) - 后端返回的图片地址(如
https://xxx.com/a.jpg)可直接用,无需处理
示例判断逻辑:
const isH5 = uni.getSystemInfoSync().platform === 'h5'
const previewUrls = this.imageList.map(path => {
if (isH5) {
const file = this.tempFiles.find(f => f.path === path)
return file ? URL.createObjectURL(file.file) : path
}
return path
})
uni.previewImage({ urls: previewUrls, current: currentUrl })
多图展示用 flex + calc 模拟 grid 布局,别依赖 gap
微信小程序、H5、App 三端对 gap 属性支持极差,尤其 iOS 微信基础库 ≥ 2.16.0 仍会忽略。强行写 gap: 8px 在真机上大概率失效,导致图片紧贴排列。
稳定方案是用 flex + calc() 控制单图宽度,并手动管理外边距:
- 三图横排:设
width: calc((100% - 16px) / 3),左右各留 8px 间隙(共两处) - 每张图加
margin-right: 8px,最后一张用:nth-child(3n)清除margin-right - 避免用
v-for的索引取模判断“是否最后一列”,改用 CSS 伪类更可靠
关键样式片段:
.image-grid {
display: flex;
flex-wrap: wrap;
}
.image-item {
width: calc((100% - 16px) / 3);
margin-right: 8px;
margin-bottom: 8px;
}
.image-item:nth-child(3n) {
margin-right: 0;
}
图片增删必须用 splice,禁用 filter
用户点击「×」删图时,如果用 this.imageList = this.imageList.filter(...),数组索引会被重排,导致 v-for 渲染错位——比如删第 2 张,第 3 张可能显示成第 2 张,预览时点错图。
根本原因是 Vue 的 key 绑定依赖数组下标,filter 会改变元素位置,而 splice 保持剩余项索引连续:
- 删图操作必须传入真实 index:
this.imageList.splice(index, 1) - 不要在模板里写
:key="index",改用唯一标识(如:key="item.id || item.path") - 如果没唯一 id,可在选图时生成:
{ path, id: Date.now() + Math.random() }
补充:H5 端删图后需调用 URL.revokeObjectURL() 释放内存,否则 blob URL 泄漏。
表单提交时图片必须单独上传,不能塞进 formData
常见错误是把 imageList 数组直接拼进 formData 发请求,结果后端收到的是 [object Object] 或空字段。因为 uni.uploadFile 的 formData 只接受字符串值,不支持数组或对象。
正确链路只有两条:
- 分步提交:先
uni.uploadFile逐个上传,收集返回的fileId或url,再用uni.request提交评价主体(含imageIds: ["id1","id2"]) - 直传模式:后端提供带签名的上传地址,前端用
uni.uploadFile直传到 OSS/COS,返回的 url 再作为字段提交
注意点:
- 每个
uni.uploadFile必须配独立name(如file0,file1),否则后端无法按序解析 - 并发上传建议 ≤ 3 个,安卓低端机容易触发
uploadFile:fail abort - 空图也要显式传
imageList: [],否则后端校验可能失败
实际排版和交互的复杂点不在结构,而在路径状态的跨平台一致性——H5 的 blob URL、小程序的临时路径、App 的本地文件路径,三者生命周期和可访问性完全不同,必须分开管理,不能靠一套逻辑硬扛。



















