vue |通过promise实现图片批量上传

需求

  • 批量上传头像,且头像能上传到对应的人员信息上
  • 上传限制
  • 不是立刻上传

修改默认样式

因为觉得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,接着前端通过图片名称来获取对应的标识进行文件上传。

这里先了解一下图片文件的数据格式:

image.png

如果不想立刻上传,那么很容易想到的办法就是先将文件储存起来:

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'}})
  })
},
posted @ 2020-12-01 15:01  sanhuamao  阅读(1295)  评论(0编辑  收藏  举报