近期,发现点击修改,element ui 的图片没有回显到框中,记载一个实现过程。
1. 图片手动上传,等待上传成功。
这里关键点设置关闭自动上传,用于手动提交,设置上传地址和请求头信息。success函数和error函数监听结果。
- :auto-upload="false":禁止自动上传
- :action=uploadUrl 设置上传地址
- :headers="headers" 设置上传请求头信息
- :file-list="form.files" 将自定义对象加入到列表中
- :on-success="handleAvatarSuccess":上传成功函数
- :on-error="handleError":上传失败函数
<el-upload
ref="upload"
:auto-upload="false"
:action=uploadUrl
:headers="headers"
:file-list="form.files"
name="file"
list-type="picture-card"
:on-progress='handPic'
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-success="handleAvatarSuccess"
:on-error="handleError"
>
逻辑实现,因为后端返回的是一个图片地址,这里新增的时候需要拿到图片上传结果,并复制给对象,进行新增,当点击提交表单后:调用submitUpload 自定义函数。作用是等待上传结果。
try {
await this.submitUpload()
} catch (e) {
this.$message.warning('请重新上传图片~~')
return
}
这里通过 Promise 实现等待效果。通过 this.$refs.upload.submit() 方法进行上传图片。
this.uploadPromiseResolve 和 this.uploadPromiseReject 是自定义参数,获取到当前Promise 的 resolve, reject 引用,从而实现等待,如果没有这两个,该函数将不会等待。当值有引用时,该对象不会被释放,从而等待。
// 包装 submit 方法,返回 Promise
async submitUpload() {
return new Promise((resolve, reject) => {
this.$refs.upload.submit()
this.uploadPromiseResolve = resolve
this.uploadPromiseReject = reject
})
},
这个时候成功上传函数或者失败函数会被调用,成功则把图片地址复制给当前表单,然后将响应结果赋值并释放,一定要释放。失败则直接释放。
//图片上传成功
handleAvatarSuccess(response) {
this.form.img = response.fileName
this.uploadPromiseResolve(response)
this.uploadPromiseResolve = null
},
handleError(error) {
this.uploadPromiseReject(error)
this.uploadPromiseReject = null
}
回到刚刚的函数中。整个流程就到完成了。
2. 回显是如何实现的?
需求是点击修改,将获取接口中的图片地址路径,进行渲染该图片。
通过 getDevice 获取到当前设备信息,有 img 属性表示图片。
接下来,调用 getImgForObject 函数,传入图片,多张图片由逗号分隔。看下具体实现。
/** 修改按钮操作 */
async handleUpdate(row) {
this.reset()
const id = row.deviceNumber || this.ids
const {data} = await getDevice(id, this.form.deviceType)
this.form = data
this.form.files = await getImgForObject(data.img)
this.title = '修改设备'
this.open = true
}
这里说下逻辑,通过获取的路径,去调用该接口,获取二进制数据,将二进制转换成 blob对象,再使用 URL.createObjectURL() 创建当前页面可访问的图片地址。为什么是当前页面可访问呢,因为这个是临时地址,只能被当前会话访问。最后封装ELement ui 需要的格式对象返回即可。
// 将二进制数据转换成可访问的Element ui 对象
export async function getImgForObject(imgs) {
if (imgs) {
return await Promise.all(
imgs.split(',').map(async item => {
const blob = await getImg(item)
// 将 Blob 对象转换为 File 对象
const split = item.split('/')
const file = new File([blob], split[split.length - 1], {type: blob.type})
// 创建唯一的 uid (可以根据实际需求生成唯一标识)
const uid = Date.now()
// 使用 URL.createObjectURL() 创建可访问的本地 url
// 这里不仅可以传blob,还可以传file
const fileUrl = URL.createObjectURL(blob)
// 构建 File 对象并返回
return {
name: file.name,
percentage: 0, // 初始上传进度为 0
raw: file, // Blob 转换为 File
size: file.size, // 文件大小
status: 'ready', // 状态设为 ready
uid: uid, // 唯一标识符
url: fileUrl // 使用 createObjectURL 生成的本地 URL
};
})
)
}
}
补充 getImg 的方法
// 获取图片的二进制数据 9.25
export function getImg(id) {
return request.get( id, { responseType: 'blob' } )
}
3. 之前的方式,发现不太好,10.22 日做二次修改
- 之前的方式,只能一次一次传递,不能一次上传多个
- 优化代码
与之前比较,关闭了默认上传方式,使用axios 进行上传。
去除了地址释放。
<el-upload multiple ref="upload" action="#"
:class="{'hide':hideUploadBtn}"
:auto-upload="false" // 关闭自动上传
:file-list="form.files" // 用于回显
:on-change="handleAddChange" // 添加时
list-type="picture-card"
:on-preview="handlePictureCardPreview" // 放大图像
:on-remove="removefile" :limit="3"> // 限制3 移除时
<i class="el-icon-plus"></i>
</el-upload>
js 逻辑
首先流程是这样的,添加图片后,将结果遍历一下,获取到raw也就是file对象,形成数组,设置img,这里设置是为了通过表单校验。
执行移除图片后,同样将遍历图片,取出来raw,形成数组。如果为 0 将 img 字段设置为 null,方便校验。
提交时,直接执行全表单校验,通过后使用 axios 进行上传获取到地址,存入 img 中。即可。
// 图片上传改变
handleAddChange(file, fileList) {
this.form.img = '表示添加了'
this.$refs.form.validateField('img')
this.fileUpload = fileList.map(item => item.raw)
//如果图片超过六张,则不显示+号
this.hideUploadBtn = fileList.length >= 6
},
/** 图片移除 */
removefile(file, fileList) {
if (fileList.length === 0) {
this.form.img = null
this.$refs.form.validateField('img')
}
this.fileUpload = fileList.map(item => item.raw)
// 上传图片 > 6 则隐藏上传组件
this.hideUploadBtn = fileList.length >= 6
},
/** 提交按钮 */
async submitForm() {
const validate = await this.$refs.form.validate()
if (validate) {
// 封装格式
const formData = new FormData()
this.fileUpload.forEach(file => formData.append('files', file))
const {fileNames} = await uploads(formData)
this.form.img = fileNames
if (this.title === '修改设备') {
await updateDevice(this.form)
await this.getList()
this.$modal.msgSuccess('修改成功')
this.open = false
} else {
await addDevice(this.form)
await this.getList()
this.$modal.msgSuccess('新增成功')
this.open = false
}
}
},