实现原理:
新建一个web api中FileReader对象,去读取本地选中的图片,新建image对象去记录选中图片的基本信息(如: width,height等),新建"canvas"标签,利用Image对象记录的数据在"canvas"上重绘一个图片,然后再将图片转成base64编码,再处理成Blob类型返回即可
具体如下(以下例子使用的是 element-ui的上传组件)
在上传文件时,监听选中图片后、上传之前的事件
// 这是在vue中的template里的代码
<el-upload
ref="upload"
<!-- // 上传地址 --></el-upload>
action="https://jsonplaceholder.typicode.com/posts/"
<!-- // 是否支持多选文件 -->
:multiple="false"
name="fileName"
<!-- // 数据 -->
:data="uploadData"
<!-- // 上传成功回调 -->
:on-success="uploadSuccess"
<!-- // 重点是监听下面的上传前的事件 -->
<!-- // 上传前的回调 -->
:before-upload="uploadHandle"
></el-upload>
监听上传前的回调,会有一个file形参,里面有上传文件的路径等信息
// 文件上传前处理
uploadHandle(file){
// 判断文件大小是否大于300kb,小于则不做处理
if (file.size <= 327200){
return
}
// 返回一个promise对象
return new Promise(resolve => {
// 用于读取本地文件的对象
const reader = new FileReader()
// 用于存储选中图片的基本信息
const image = new Image()
image.onload = (imageEvent) => {
// 创建canvas标签元素
const canvas = document.createElement('canvas')
// 制定绘制的类型 这边指定的是2d类型
const context = canvas.getContext('2d')
// imgQuality 指缩放的比例,我这边设置了0.5,最好用变量去定义,这样容易维护
const width = image.width * this.imgQuality // 0.5
const height = image.height * this.imgQuality // 0.5
canvas.width = width
canvas.height = height
// 清除canvas的矩形内容(将canvas上的东西清除)
context.clearRect(0,0,width,height)
// 在canvas中,按指定的比例去画出图片
context.drawImage(image,0,0,width,height)
// 将canvas画出的图片转成base64
const dataUrl = canvas.toDataURL(file.type)
// 把base64 dataUrl格式转换成blob类型(dataUrlToBlob方法在下面)
const blobData = this.dataUrlToBlob(dataUrl,file.type)
// 返回blobData进行上传
resolve(blobData)
}
// 读取完文件后,将图片的路径存到新建的image上
reader.onload = (e => {image.src = e.target.result})
// 根据路径读取选中的文件
reader.readAsDataURL(file)
})
},
// 把base64 dataUrl格式转换为blob类型
dataUrlToBlob(dataUrl,type){
// 使用window的atob方法去解码base64
let binary = atob(dataUrl.split(',')[1])
let arr = []
// 转unicode编码
for (let i = 0; i < binary.length; i++) {
arr.push(binary.charCodeAt(i))
}
// 通过unicode编码去创建Blob类型
return new Blob([new Uint8Array(arr)],{type})
}