用element的upload組件實現多圖片上傳和壓縮

我用vuex作狀態管理,七牛雲作圖牀。前端

項目地址:多圖片上傳組件vue

效果展現

圖片描述

項目執行流程

首先,讓咱們來分析一下實現多圖片上傳的流程:python

  • 前端向後端請求用來上傳圖片至服務器的token
  • 後端爲每張要上傳的圖片生成一個圖片名,並用這個圖片名生成token
  • 後端將圖片名和token返回給前端
  • 前端拿到token之後,將圖片上傳至服務器
  • 上傳成功之後,前端將圖片名發給後端
  • 後端將圖片名存入數據庫

圖片描述

項目實現過程

1.咱們要利用element-ui的Upload組件佈置界面:git

//upload.vue
<el-upload
  :action= domain
  ref="upload"
  accept='image/jpeg,image/gif,image/png'
  :auto-upload="false"
  :http-request="upqiniu"
  :limit="limit"
  :multiple="multiple"
  list-type="picture-card"
  :before-upload="beforeUpload"
  :on-preview="handlePictureCardPreview"
  :on-change="handldChange"
  :on-remove="handleRemove">
  <i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
  <img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>

domain 指的是咱們的上傳地址,upqiniu 是咱們自定義的上傳方法,beforeUpload 是圖片上傳前執行的方法。關於該組件的其餘用法能夠在element的官方文檔查閱:Upload 上傳github

2.對圖片進行壓縮vuex

// upload.vue
imgQuality: 0.5, //壓縮圖片的質量

dataURItoBlob(dataURI, type) {
  var binary = atob(dataURI.split(',')[1]);
  var array = [];
  for(var i = 0; i < binary.length; i++) {
    array.push(binary.charCodeAt(i));
  }
  return new Blob([new Uint8Array(array)], {type: type});
},

beforeUpload(param) {
  //對圖片進行壓縮
  const imgSize = param.size / 1024 / 1024
  if(imgSize > 1) {
    const _this = this
    return new Promise(resolve => {
      const reader = new FileReader()
      const image = new Image()
      image.onload = (imageEvent) => {
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        const width = image.width * _this.imgQuality
        const height = image.height * _this.imgQuality
        canvas.width = width;
        canvas.height = height;
        context.clearRect(0, 0, width, height);
        context.drawImage(image, 0, 0, width, height);
        const dataUrl = canvas.toDataURL(param.type);
        const blobData = _this.dataURItoBlob(dataUrl, param.type);
        resolve(blobData)
      }
      reader.onload = (e => { image.src = e.target.result; });
      reader.readAsDataURL(param);
    })
  }
}

壓縮圖片實現起來比較簡單。就是在beforeUpload()方法裏面return一個Promise,Promise裏面咱們把圖片的長度和寬度按比例進行縮小,並把圖片畫到canvas上,而後把canvas轉成一個blod對象。數據庫

3.前端向後端請求上傳token。element-ui

//upload.vue
upqiniu(param) {
  let filetype = ''
  if (param.file.type === 'image/png') {
    filetype = 'png'
  } else {
    filetype = 'jpg'
  }
  const formdata = {
    filetype: filetype,
    param: param
  }
  this.actionGetUploadToken(formdata)        
}

// vuex/action.js
actionGetUploadToken({commit}, obj) {
  const msg = {
    filetype: obj.filetype
  }
  usersApi.getImgUploadToken(msg).then((response) => {
    if(response.stateCode === 200) {
      commit('uploadImg', {'token': response.token, 'key': response.key, 'param': obj.param})
    } 
  }, (error) => {
    console.log(`獲取圖片上傳憑證錯誤:${error}`)
    commit('uploadImgError')
  })
},

4.後端生成上傳token,併發給前端,我用Python實現。canvas

filetype = data.get('filetype')
# 構建鑑權對象
q = Auth(configs.get('qiniu').get('AK'), configs.get('qiniu').get('SK'))

# 生成圖片名
salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
key = salt + '_' + str(int(time.time())) + '.' + filetype

# 生成上傳 Token,能夠指定過時時間等
token = q.upload_token(configs.get('qiniu').get('bucket_name'), key, 3600)
return Response({"stateCode": 200, "token": token, "key": key}, 200)

5.前端接收token,開始向服務器上傳圖片後端

// vuex/state.js
imgName: [], //圖片名數組

// vuex/mutations.js
uploadImg(state, msg) {
  const config = {
    useCdnDomain: true,
    region: qiniu.region.z2
  }
  var putExtra = {
    fname: msg.param.file.name,
    params: {},
    mimeType: ["image/png", "image/jpeg", "image/gif"]
  };
  var observer = {
    next(res){

    },
    error(err){
      console.log(`圖片上傳錯誤信息:${err.message}`)
    }, 
    complete(res){
      console.log(`圖片上傳成功:${res.key}`)
      state.imgName.push(res.key)
    }
  }
  var observable = qiniu.upload(msg.param.file, msg.key, msg.token, putExtra, config)
  //上傳開始
  var subscription = observable.subscribe(observer)
},

6.上傳成功之後,將圖片名存入數據庫

// 用到upload.vue的界面
this.imgsList = this.imgName.map(key => `http://${this.qiniuaddr}/${key}`)
switch(this.imgsList.length) {
  case 4:
  this.img4 = this.imgsList[3]
  case 3:
  this.img3 = this.imgsList[2]
  case 2:
  this.img2 = this.imgsList[1]
  case 1:
  this.img1 = this.imgsList[0]
}
let obj = {
  goods_img1: this.img1,
  goods_img2:this.img2,
  goods_img3:this.img3,
  goods_img4:this.img4
}
//將信息發送給後端
this.actionPublish(obj)
相關文章
相關標籤/搜索