需求
- 批量上传头像,且头像能上传到对应的人员信息上
- 上传限制
- 不是立刻上传
修改默认样式
因为觉得element组件的el-upload
有点复杂,所以这里使用原始的input
标签。不过通常需要换掉原始样式,只需给input
添加一条style="display:none"
,接着用具有其他样式的元素包裹它,并在该元素上添加事件(不包裹也行,包裹主要是为了容易看)。
<el-button @click="beforeImagesUpload">批量上传图片
<input type="file" style="display:none" id="file" multiple>
</el-button>
点击触发该事件相当于点击了里面的input元素
beforeImagesUpload(){
let file = document.querySelector('#file')//获取最原始的input元素
file.click()//触发
}
保存图片信息
现在要在上面的beforeImagesUpload
进行丰富。由于我希望头像能上传到对应的人员信息上,那么我至少需要有一个标识帮助我识别这个头像属于谁。所以上传前先要求用户将图片命名为对应的id,接着前端通过图片名称来获取对应的标识进行文件上传。
这里先了解一下图片文件的数据格式:
如果不想立刻上传,那么很容易想到的办法就是先将文件储存起来:
fileList:[]
async beforeImagesUpload(){
let fileList=[]
let file = document.querySelector('#file')
file.click()
file.onchange = function (event) {
let files = event.target.files
for(let i=0;i<files.length;i++){
let file=files[i]
let filename=file.name//获取图片名称(有后缀)
let id=filename.slice(0,filename.indexOf('.'))//获取图片名称(无后缀)
fileList.push({file:file,id:id,filename:filename})//整合成新的图片对象,并将其加进图片列表中
}
}
console.log(fileList)//出错
}
然而,你会发现控制台打印数据是空的。这是由于同步致使函数直接跳过处理图片的部分,马上到了后面的console.log(fileList)
Promise实现异步
这时可以使用promise
对象解决。promise
对象的函数内有两个参数:resolve和reject,它们是两个回调函数,前者表示成功时的回调,后者表示失败时的回调,这里先不考虑reject的情况:
async beforeImagesUpload(){
let that=this//改变作用域
let promise= new Promise(function (resolve, reject) {
let fileList=[]
let file = document.querySelector('#file')
file.click()
file.onchange = function (event) {
let files = event.target.files
for(let i=0;i<files.length;i++){
let file=files[i]
let filename=file.name
let id=filename.slice(0,filename.indexOf('.'))
fileList.push({file:file,id:id,filename:filename})
}
resolve(fileList)//通过resolve将fileList抛出,在后续使用
}
})
//接着就是处理抛出来的数据了:
//promise接受两个回调函数作为参数:一个状态变为Resolved时调用,一个是状态变为Reject时调用。
//这两个函数都接受Promise对象传出的值作为参数。
//第二个函数是可选的,这里先不考虑第二个函数。
promise.then(function(value) {
//状态为resolved时调用,这里的value就是resolve抛出的数据
console.log(value)//成功打印
that.fileList=value//储存
});
},
为了更好的处理数据,建议把value传给另一个函数处理:
promise.then(function(value) {
that.upload(value)//正式上传 后面写
}
)
添加限制
假设上传图片有两个前提:
1.最多只能上传10张
2.图片大小不能大于300k
这里reject
就派上用场的了。现在修改一下promise对象中的内容:
//...
let promise= new Promise(function (resolve, reject) {
//...
file.onchange = function (event) {
let files = event.target.files
//1.判断图片数量
if(files.length>10){
reject('page')//如果多于10张,判定为失败,抛出错误'page',停止向下运行。
}else{
for(let i=0;i<files.length;i++){
let file=files[i]
//2.判断图片大小
const is300K=file.size>300*1024//判定指标,是否大于300k
if (is300K) {
reject('size')//如果大于300k,判定为失败,抛出错误'size',停止向下运行。
}
let fileName=file.name
let phone=fileName.slice(0,fileName.indexOf('.'))
fileList.push({file:file,phone:phone,fileName:fileName})
}
}
resolve(fileList)//上面均没有出错时抛出
}
})
接下来就是处理回调函数:
async beforeImagesUpload(){
//...
let promise= new Promise(function (resolve, reject) {
//...
})
//这里需要promise的第二个回调函数,在状态为Reject时调用:
promise.then(function(value) {
that.upload(value)//正式上传
}, function(error) {
//上面设置了两种错误,这里可以用if来判断错误类型,并给出对应的响应
if(error=='page'){
that.$message.error('最多只能上传10张照片!')
}else if(error=='size'){
that.$message.error('上传的图片大小不能超过300K!');
}
});
},
图片上传
不是立刻上传,需要将upload(value)
传过来的值先保存起来,如this.fileList=value
,再经过中间函数处理,配合弹框使用。
为了简便,这里就直接上传了。批量上传,说白了其实就是一个一个地上传,这里我使用的是axios
插件:
upload(value){
value.map(item=>{
let fd = new FormData()
fd.append('image',item.file)
fd.append('id',item.id)
axios.post("url",fd,{headers:{'Content-Type': 'multipart/form-data'}})
})
},