虽然标题里面有若依,实际上所有的Vue项目都能够适用的。
最近基于若依系统做点东西,若依系统本身封装了一个图片上传组件ImageUpload
,但是这个组件对我来说不太适用,最主要的问题就是这个组件是自动上传的,这样就会导致我们业务数据跟附件无法做到同步,比如我们新增一个单据,点了上传图片,此时图片已经上传到服务器,但是我并没有保存单据,这样就造成了部分垃圾数据。当然不是说不能处理,只是来说更加麻烦。
先来说下我们目前做的功能需求吧:
- 基于ElementUI的
el-upload
上传图片 - 为了减少图片占用的空间(目前基于阿里云OSS,这个后期介绍),我们在前端上传图片之前在不影响图片展示质量的前提下,对图片进行压缩
- 表单数据与图片文件同步上传
- 可以单张图片上传也可以同时上传多张图片(以下我们以多张图片上传来说明)
壹、提取图片压缩公共方法
在ruoyi.js
公共方法中,封装图片压缩方法
/** 图片压缩,默认同比例压缩
* @param {Object} fileObj
* 图片对象
* 回调函数有一个参数,base64的字符串数据
*/
export function compress(fileObj, callback) {
// console.log('压缩前文件大小', fileObj.size)
try {
const image = new Image()
image.src = URL.createObjectURL(fileObj)
image.onload = function () {
const that = this
// 默认按比例压缩
let w = that.width
let h = that.height
const scale = w / h
w = fileObj.width || w
h = fileObj.height || (w / scale)
let quality = 0.5 // 默认图片质量为0.7
// 生成canvas
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
// 创建属性节点
const anw = document.createAttribute('width')
anw.nodeValue = w
const anh = document.createAttribute('height')
anh.nodeValue = h
canvas.setAttributeNode(anw)
canvas.setAttributeNode(anh)
ctx.drawImage(that, 0, 0, w, h)
// 图像质量
if (fileObj.quality && fileObj.quality <= 1 && fileObj.quality > 0) {
quality = fileObj.quality
}
// quality值越小,所绘制出的图像越模糊
const data = canvas.toDataURL('image/jpeg', quality)
// 压缩完成执行回调
const newFile = convertBase64UrlToBlob(data)
callback(newFile)
// console.log('压缩后文件信息', newFile)
}
} catch (e) {
console.log('压缩失败!')
}
}
// Base64 => 二进制(Blob)
function convertBase64UrlToBlob(urlData) {
// 去掉url的头,并转换为byte
const bytes = window.atob(urlData.split(',')[1])
// 处理异常,将ascii码小于0的转换为大于0
const ab = new ArrayBuffer(bytes.length)
const ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
return new Blob([ab], {type: 'image/png'})
}
在main.js
中挂载公共方法,方便在后面使用
Vue.prototype.compress = compress
贰、页面增加上传图片功能
在表单中,增加上传图片功能
<el-upload action="#" list-type="picture-card" :auto-upload="false" multiple :headers="headers"
ref="carPhotoListRef" :on-preview="handlePictureCardPreview" :on-remove="handleRemove"
:on-change="handleChange" :file-list="imageFileList"
:disabled="form.inquiryStatus !== 'inquirying'"
:class="{ hide: form.inquiryStatus !== 'inquirying' }"
accept="image/bmp,image/jpg,image/png,image/svg,image/psd,image/webp,image/jpeg">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogImageVisible" :append-to-body="true">
<img width="100%" :src="dialogImageUrl" alt=""/>
</el-dialog>
因为我们要手工上传图片,所以需要对el-upload
的属性进行配置
action
因为我们要收工上传,所以action
需要设置成#
auto-upload
设置成false
禁止自动上传
headers
是基于若依的认证,传递头部信息的
on-preview
预览图片
on-remove
删除图片同步处理我们后端绑定数据
on-change
图片改变的钩子,因为我们要手工上传图片,因此通过这个钩子完成图片的压缩
其他的一些属性基本设置图片预览,限制上传图片类型的,按需设置即可。
data
里面主要设置图片预览、绑定图片列表等属性
data() {
return {
headers: {
Authorization: "Bearer " + getToken()
},
//预览图片窗口是否可见
dialogImageVisible: false,
//预览图片Url
dialogImageUrl: null,
imageFileList: [],
}
}
method
方法如下
//删除图片
handleRemove(file, fileList) {
this.imageFileList = fileList
if (this.form.carPhotoList) {
let index = -1
for (let i = 0; i < this.form.carPhotoList.length; i++) {
if (this.form.carPhotoList[i].photoId === file.photoId) {
index = i
}
}
if (index !== -1) {
this.$delete(this.form.carPhotoList, index)
}
}
},
//图片改变
handleChange(file, fileList) {
let that = this
// 调用自定义的压缩方法
compress(file.raw, function (val) {
// 图片格式: blob => file
let newFile = new window.File([val], file.name, {type: file.raw.type});
// 新增属性(file)并赋值
let fileObj = {}
fileObj.raw = newFile
fileObj.name = file.name
fileObj.uid = file.uid;
fileObj.url = URL.createObjectURL(file.raw);
that.imageFileList.push(fileObj)
})
// this.imageFileList = fileList
},
//预览图片
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogImageVisible = true
},
实现图片压缩主要是通过on-change
钩子,选择图片后,通过on-change
钩子调用handleChange
方法,我们拿到图片文件后,调用compress
方法,通过回调函数,将压缩后的图片绑定到imageFileList
表单保存
/** 提交按钮 */
submitForm() {
if (this.imageFileList.length <= 0) {
this.msgInfo('请上传图片')
return
}
const loading = this.$loading({
lock: true,//lock的修改符--默认是false
text: "保存中",//显示在加载图标下方的加载文案
spinner: "el-icon-loading",//自定义加载图标类名
background: "rgba(0, 0, 0, 0.7)",//遮罩层颜色
target: document.querySelector("#table")//loadin覆盖的dom元素节点
})
this.$refs["form"].validate(valid => {
if (valid) {
let formData = new FormData()
this.imageFileList.forEach(file => {
formData.append("imageFileList", file.raw)// 图片列表
})
formData.append("form", JSON.stringify(this.form))//表单
if (this.form.inquiryId != null) {
updateInquiry(formData).then(response => {
loading.close()
this.msgSuccess("修改成功")
this.open = false
this.getList()
}).catch(error => {
loading.close()
})
} else {
addInquiry(formData).then(response => {
loading.close()
this.msgSuccess("新增成功")
this.open = false
this.getList()
}).catch(error => {
loading.close()
})
}
} else {
loading.close()
}
})
},
在表单保存方法中,我们通过FormData
将图片文件与表单数据,一起保存。
评论 (0)