使用FormData数据做图片上传: new FormData() canvas实现图片压缩

使用FormData数据做图片上传: new FormData()       canvas实现图片压缩

ps: 千万要使用append不要用set   苹果ios有兼容问题导致数据获取不到,需要后台接口支持formData数据 Content-Type: multipart/form-data

 正确的打开方式:formdata.append('file', file)

错误的打开方式:formData.set(name,value) 

//html代码
<div class="sendImage" slot="label">
              <input type="file" name="file" accept="image/*" ref="ndImgUpload"
                     class="upload_input" @change="imgSelectChange">
            </div>



//**************javascript代码 Begin**********************

//************* tool.js文件   canvas实现图片压缩***********

//    用于压缩图片的canvas
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d');
//    瓦片canvas
let tCanvas = document.createElement("canvas");
let tctx = tCanvas.getContext("2d");


 // /**
 //  *  ************ js图片压缩类*****************
 // */
export function compress (img) {
  let initSize = img.src.length;
  let width = img.width;
  let height = img.height;

//如果图片大于四百万像素,计算压缩比并将大小压至400万以下
  let ratio;
  if ((ratio = width * height / 4000000) > 1) {
    ratio = Math.sqrt(ratio);
    width /= ratio;
    height /= ratio;
  } else {
    ratio = 1;
  }

  canvas.width = width;
  canvas.height = height;

//        铺底色
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

//如果图片像素大于100万则使用瓦片绘制
  let count;
  if ((count = width * height / 1000000) > 1) {
    count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片

//            计算每块瓦片的宽和高
    let nw = ~~(width / count);
    let nh = ~~(height / count);

    tCanvas.width = nw;
    tCanvas.height = nh;

    for (let i = 0; i < count; i++) {
      for (let j = 0; j < count; j++) {
        tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);

        ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
      }
    }
  } else {
    ctx.drawImage(img, 0, 0, width, height);
  }

  //进行压缩toDataURL:值越小,压缩力度越大
  let ndata = canvas.toDataURL('image/jpeg', 0.7);

  console.log('压缩前:' + initSize);
  console.log('压缩后:' + ndata.length);
  console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");

  tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;

  return ndata;
}

/**
 * 将以base64的图片url数据转换为Blob
 * @param urlData
 * 用url方式表示的base64图片数据
 */
export function convertBase64UrlToBlob (urlData) {
  let arr = urlData.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = window.atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], {type: mime});
}




  /**
   *  ***********业务代码开始************
   */

  import {compress, convertBase64UrlToBlob} from 'utils/tool'
  const UPLOAD_IMG_SIZE = 10          //图片上传大小不能大于10M
  const IMG_NEED_COMPRESS_SIZE = 0.5  //图片大小<=0.5M,则不压缩,直接上传
  const SELECT_IMG_QUANTITY = 9       //发送消息图片最多选9张


//  *************vue代码  ***************

methods:{
 imgSelectChange (e) {
        this.$vux.loading.show({
          text: 'Loading'
        })

        let file = e.target

        setTimeout(() => { //加500ms定时器是为了防止大质量图片上传会造成卡顿loading会延迟执行
          this.sendImgIndex = 0

          if (file.files.length > SELECT_IMG_QUANTITY) {
            this.$vux.loading.hide()
            return this.$vux.alert.show({
              title: '提示',
              content: '最多选9张图片',
              onHide () {
                file.value = ''
              }
            })
          }

          for (let obj of Array.from(file.files)) {

            if (!/\/(?:jpeg|png|gif|jpg)/i.test(obj.type)) {
              this.$vux.loading.hide()
              return this.$vux.alert.show({
                title: '提示',
                content: `${obj.name}不是图片文件类型`,
                onHide () {
                  file.value = ''
                }
              })
            }

            let calcSize = obj.size / 1024 / 1024
            if (calcSize > UPLOAD_IMG_SIZE) {
              this.$vux.loading.hide()
              return this.$vux.alert.show({
                title: '提示',
                content: `图片大小不能大于${UPLOAD_IMG_SIZE}M`,
                onHide () {
                  file.value = ''
                }
              })
            }

          }

          const imgLen = file.files.length
          this.eachSendImg(file.files, file, (data) => {

            //msgType 0系统 1文字 2图片 3音频 4视频 5回撤
            this.sendMsgHandle(2, data, () => {
              this.sendImgIndex === imgLen && this.$vux.loading.hide()
            }, () => {
              this.sendImgIndex === imgLen && this.$vux.loading.hide()
              this.$vux.alert.show({
                title: '提示',
                content: `图片${file.files[this.sendImgIndex - 1].name}发送消息失败`
              });
            })

          }, (err) => {

          })
        }, 500)
      },
 eachSendImg (files, input, success, error) {
        if (!files.length) return
        let that = this
        let args = arguments

        that.sendImg(files[that.sendImgIndex]).then(data => {
          success(data)
          that.sendImgIndex++
          files[that.sendImgIndex] ? that.eachSendImg.apply(that, args) : input.value = ''

        }).catch(err => {
          that.$vux.loading.hide()

          let txt_tip = err.msg === 'FILE_WRONG_SIZE' ? `图片${files[that.sendImgIndex].name}文件过大,上传失败`
            : `图片${files[that.sendImgIndex].name}上传失败`;

          that.$vux.alert.show({
            title: '提示',
            content: txt_tip,
            onHide () {
              error(err)
              that.sendImgIndex++

              if (files[that.sendImgIndex]) {
                that.$vux.loading.show({
                  text: 'Loading'
                })
                that.eachSendImg.apply(that, args)
              } else {
                input.value = ''
              }

            }
          })

        })

      },
 sendImg (file) {

        let formdata = new FormData(); // FormData 对象
        let that = this

        return new Promise((resolve, reject) => {

          if (file.size / 1024 / 1024 <= IMG_NEED_COMPRESS_SIZE) {

            formdata.append('file', file)
            that.sendImgAjax(formdata).then((res) => {
              resolve(res)
            }).catch((err) => {
              reject(err)
            })
            return;
          }

          let reader = new FileReader();
          reader.onload = function () {
            let result = this.result;
            let img = new Image();
            img.src = result;

            //   图片加载完毕之后进行压缩,然后上传
            if (img.complete) {
              let data = compress(img);

              let blob = convertBase64UrlToBlob(data);
              formdata.append("file", blob, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
              that.sendImgAjax(formdata).then((res) => {
                resolve(res)
              }).catch((err) => {
                reject(err)
              })

              img = null;
            } else {
              img.onload = () => {
                let data = compress(img);

                let blob = convertBase64UrlToBlob(data);
                formdata.append("file", blob, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
                that.sendImgAjax(formdata).then((res) => {
                  resolve(res)
                }).catch((err) => {
                  reject(err)
                })

                img = null;
              };
            }

          }
          reader.readAsDataURL(file);
        })
      },
 sendImgAjax (formData) {
        return new Promise((resolve, reject) => {
          getData.common.form_uploadImg({
            data: formData,
            sucCb (data) {
              resolve(data)
            },
            failCb (err) {
              reject(err)
            }
          })
        })
      },
 sendMsgHandle (type, msg, success, error) {//发送消息
        if (!this.inputVal.trim() && !msg) return this.$vux.toast.text('消息内容不能为空');
        this.disabled = true

        this.$vux.loading.show({
          text: 'Loading'
        })

        if (this.query.groupId) {
          let that = this
          getData.doctor.group_chat_send_msg({
            params: {
              gid: that.query.groupId,
              //msg{1 || 0} :如果是图片上传,数据转为字符串,包含宽高url,msgType
              msg: msg ? JSON.stringify(msg) : that.inputVal,
              type //msgType 0系统 1文字 2图片 3音频 4视频 5回撤
            },
            sucCb (data) {
              msg && (data.msg = JSON.parse(data.msg)) //如果是图片上传,msg消息数据为对象转的字符串
              that.data.push({
                chatid: data.uid,
                from: data.uid,
                content: msg ? data.msg.url : data.msg,
                width: msg ? data.msg.width : 0,
                height: msg ? data.msg.height : 0,
                create_time: data.date,
                avatar: data.pic,
                name: data.nick,
                group_id: data.gid,
                msg_id: data.id,
                msg_type: data.type
              })

              that.addPrevTimeData()
              that.setLocalData(that.query.groupId, that.data.slice(-1))

              type !== 2 && that.$vux.loading.hide()
              that.disabled = false
              that.inputVal = ''

              success && success()
            },
            failCb (err) {
              type !== 2 && that.$vux.loading.hide()
              that.disabled = false
              let overtime = err.code * 1 === 0

              if (that.inGoBackError(err.code) || overtime) {
                type === 2 && that.$vux.loading.hide()

                that.$vux.alert.show({
                  title: '提示',
                  content: overtime ? '发送失败,请检查网络' : err.code === 'USER_NOT_IN_GROUP' ? '您已被移出群聊' : err.msg,
                  onHide () {
                    !overtime && that.$router.replace({
                      path: '/spa/msgGroup'
                    })
                  }
                });
              } else if (type === 2) {
                error && error()
              } else {
                that.$vux.loading.hide()
                that.$vux.alert.show({
                  title: '提示',
                  content: '消息发送失败'
                });
              }

            }
          })
        }
      }
    
}

  

posted @ 2018-05-28 11:30  MrZou  阅读(2365)  评论(0编辑  收藏  举报