美文网首页
vue+elementui+web上传图片压缩

vue+elementui+web上传图片压缩

作者: 小话001 | 来源:发表于2021-06-08 22:33 被阅读0次

注意事项:未解决PNG带通道透明图片压缩后黑屏的问题,网上有评论说绘制背景色白色

context.fillStyle = '#fff'

个人觉得意义不大,因为只要是做设计的都明白透明通道和白色背景不是同一个概念。
为啥不支持PNG?
点击此处查看原因

原因总结:会用到toDataURL('image/jpeg',qualitys)的一个方法

在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92,其他参数会被忽略。
文件工具:compress.js

export default {
  compressImg: function(file, quality) {
    var qualitys = 0.52
    // console.log(parseInt((file.size / 1024).toFixed(2)))
    if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
      qualitys = 0.85
    }
    if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
      qualitys = 0.92
    }
    if (quality) {
      qualitys = quality
    }
    if (file[0]) {
      return Promise.all(
        Array.from(file).map(e => this.compressImg(e, qualitys))
      ) // 如果是 file 数组返回 Promise 数组
    } else {
      return new Promise(resolve => {
        // console.log(file)
        if ((file.size / 1024).toFixed(2) < 300) {
          resolve({
            file: file
          })
        } else {
          const reader = new FileReader() // 创建 FileReader
          reader.onload = ({ target: { result: src } }) => {
            const image = new Image() // 创建 img 元素
            image.onload = async () => {
              const canvas = document.createElement('canvas') // 创建 canvas 元素
              const context = canvas.getContext('2d')
              var targetWidth = image.width
              var targetHeight = image.height
              var originWidth = image.width
              var originHeight = image.height
              if (
                1 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
                parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024
              ) {
                var maxWidth = 1600
                var maxHeight = 1600
                targetWidth = originWidth
                targetHeight = originHeight
                // 图片尺寸超过的限制
                if (originWidth > maxWidth || originHeight > maxHeight) {
                  if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更宽,按照宽度限定尺寸
                    targetWidth = maxWidth
                    targetHeight = Math.round(
                      maxWidth * (originHeight / originWidth)
                    )
                  } else {
                    targetHeight = maxHeight
                    targetWidth = Math.round(
                      maxHeight * (originWidth / originHeight)
                    )
                  }
                }
              }
              if (
                10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
                parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024
              ) {
                maxWidth = 1400
                maxHeight = 1400
                targetWidth = originWidth
                targetHeight = originHeight
                // 图片尺寸超过的限制
                if (originWidth > maxWidth || originHeight > maxHeight) {
                  if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更宽,按照宽度限定尺寸
                    targetWidth = maxWidth
                    targetHeight = Math.round(
                      maxWidth * (originHeight / originWidth)
                    )
                  } else {
                    targetHeight = maxHeight
                    targetWidth = Math.round(
                      maxHeight * (originWidth / originHeight)
                    )
                  }
                }
              }
              canvas.width = targetWidth
              canvas.height = targetHeight
              context.clearRect(0, 0, targetWidth, targetHeight)
              context.fillStyle = '#fff'
              context.drawImage(image, 0, 0, targetWidth, targetHeight) // 绘制 canvas
              
              const canvasURL = canvas.toDataURL('image/jpeg', qualitys)
              const buffer = atob(canvasURL.split(',')[1])
              let length = buffer.length
              const bufferArray = new Uint8Array(new ArrayBuffer(length))
              while (length--) {
                bufferArray[length] = buffer.charCodeAt(length)
              }
              const miniFile = new File([bufferArray], file.name, {
                type: 'image/jpeg'
              })
              console.log({
                file: miniFile,
                origin: file,
                beforeSrc: src,
                afterSrc: canvasURL,
                beforeKB: Number((file.size / 1024).toFixed(2)),
                afterKB: Number((miniFile.size / 1024).toFixed(2)),
                qualitys: qualitys
              })
              resolve({
                file: miniFile,
                origin: file,
                beforeSrc: src,
                afterSrc: canvasURL,
                beforeKB: Number((file.size / 1024).toFixed(2)),
                afterKB: Number((miniFile.size / 1024).toFixed(2))
              })
            }
            image.src = src
          }
          reader.readAsDataURL(file)
        }
      })
    }
  }
}

上述工具返回的是一个promise对象.
在你封装好的的uploader.vue组件中使用

import Compress from '@/utilities/compress.js'

关键点:因为异步的原因,我们无法在elementui 上传组件的 beforeUpload()方法中使用,必须使用自定义的方法上传,覆盖掉组件的上传方法

<template>
  <div class="container">
    <el-upload :multiple="multiple" :accept="types.join(',')"  :show-file-list="showFileList" :action="$root.settings.DOMAIN_APIS.Violet + '/security/upload/temporary'" :data="{ cloud: 'violet', micro: micro}" :headers="{'access-token': $store.getters.access_token,}" :before-upload="beforeUpload" :on-success="onSuccess" :on-error="onError" :on-remove="onRemove">
      <el-button>
        <i class="el-icon-upload"></i>
        {{btnText}}
      </el-button>
    </el-upload>
    <div class="customFileList" v-if="!showFileList">
      <p v-for="(item,index) in fileList" :key=index class="fileList">
        <a :href="$root.settings.DOMAIN_IMG_FILE+item.Url" target="_blank">{{item.Name}}</a>
        <i class="el-icon-delete" @click="deleteButton(item.url)"></i>
      </p>
    </div>
  </div>
</template>
<script>
import {OSS_URL} from '@/apis/violet'

// :http-request="uploadSectionFile"
import Compress from '@/utilities/compress.js'
export default {
  props: {
    // 是否使用ui框架上传列表,默认使用,但无预览功能
    showFileList: {
      type: Boolean,
      default: true
    },
    fileList: {
      type: Array,
      default: () => ([])
    },
    types: {
      // 文件类型,默认图片jpeg,jpg,png
      type: Array,
      default: () => (['image/jpeg', 'image/jpg', 'image/png'])
    },
    multiple: {
      type: Boolean,
      default: false
    },
    micro: {
      // 上传目录
      type: String,
      default: 'security'
    },
    fileSize: {
      // 文件大小限制 单位MB
      type: Number,
      default: 2
    },
    btnText: {
      type: String,
      default: '上传文件'
    }
  },
  data() {
    return {
      loading: false,
    }
  },
  methods: {
    uploadFile(copyFile){
        console.log(copyFile)
    },
    uploadSectionFile(params) {
      console.log(params)
      const file = params.file,
        fileType = file.type,
        isImage = fileType.indexOf("image") != -1,
        isLt2M = file.size / 1024 / 1024 < 20
      // 这里常规检验,看项目需求而定
      if (!isImage) {
        this.$message.error("只能上传图片格式png、jpg、gif!");
        return
      }
      if (!isLt2M) {
        this.$message.error("只能上传图片大小小于2M");
        return
      }
      // 真正要做压缩图片大小的地方
      Compress.compressImg(file).then((res) => {
          console.log(file)
          const copyFile = res.file
           imageUpload(copyFile)
        })
      const imageUpload = (copyFile) => {
        const apiFoo = OSS_URL
         let data={ cloud: 'violet', micro: this.micro,file:copyFile}
           return apiFoo(data).then(res => {
            if (res.data.Code === 'CORRECT') {
                   console.log(res)
            }
          })
      }
      this.loading=true
    },
    beforeUpload(file) {
      if ((file.type && !this.types.includes(file.type)) || (!file.type && !this.types.includes(`.${file.name.split('.')[1]}`))) {
        this.$message.error('请上传正确文件!')
        return false
      }
      if (file.size / 1024 / 1024 > this.fileSize) {
        this.$message.error(`文件大小不能超过${this.fileSize}MB!`)
        return false
      }


      // 理论上在这个压缩图片大小,实际上beforeUpload没有用到,
      // return new Promise((resolve, reject) => {
      //   Compress.compressImg(file).then((res) => {
      //     console.log(res.file)
      //     file = res.file
      //     console.log(file)
      //      // resolve()
      //      const copyFile = file
      //      this.uploadFile(copyFile)
      //      return false
      //   })
      // })
  
      this.loading = true
    },
    onSuccess(res, file) {
      if (res.Code == 'CORRECT') {
        this.getBase64Image(file.raw).then(result => {
          res.Data.Subset.forEach(item => {
            this.$emit('onSuccess', item.Rel, result, file)
          })
        })
      } else {
        this.$message.error(res.Message)
      }
      this.loading = false
    },
    onError() {
      this.loading = false
      this.$message.error('上传失败,请稍后重试!')
    },
    onRemove(file) {
      if (file && file.status === 'success') {
        this.$emit('onRemove', file.url)
      }
    },
    getBase64Image(img) {
      return new Promise((calback) => {
        var reader = new FileReader()
        reader.readAsDataURL(img) // 转化二进制流,异步方法
        reader.onload = function () { // 完成后this.result为二进制流
          calback(this.result)
        }
      })
    },
    deleteButton(url) {
      this.$emit('onRemove', url)
    }
  }
}
</script>
<style lang="scss" scoped>
.upload-img {
  position: relative;
  border: 1px dashed $border-color;
  box-sizing: content-box;
  cursor: pointer;
  &:hover {
    border-color: $light-blue;
  }
  border-radius: 6px;
  /deep/ .el-upload {
    width: 100%;
    height: 100%;
    i {
      display: inline-block;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: #8c939d;
      font-size: $middle-font;
    }
    img {
      display: block;
      width: 100%;
      height: 100%;
    }
  }
  /deep/ .el-loading-spinner {
    margin-top: -25px;
  }
}
/deep/ .fileList {
  display: flex;
  justify-content: space-between;
  .el-icon-delete:hover {
    cursor: pointer;
  }
  .el-icon-delete {
    margin-right: 20px;
  }
}
</style>

额外记录,与当前文章无关

// violet.js
export const OSS_URL = (parameters) => {
  return fetch({
    cloud: 'Violet',
    url: '/security/upload/temporary',
    method: 'post',
    data: parameters,
  })
}
//fetch.js
  headers: {
    'X-Requested-With': 'XMLHttpRequest',
    // 'Content-Type': 'application/json; charset=utf-8',
    'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary5J9Z4y1jAznANNwp',
  }
if (config.method === 'post') {
      //config.data = JSON.stringify(config.data)
      const formdata = new FormData()
      formdata.append('cloud', 'violet'),
      formdata.append('micro', 'agiles'),
      formdata.append('file', config.data.file),
      config.data=formdata
    }
//demandAdd.vue
:fileSize=20 

相关文章

  • vue+elementui+web上传图片压缩

    注意事项:未解决PNG带通道透明图片压缩后黑屏的问题,网上有评论说绘制背景色白色 context.fillStyl...

  • iOS 网络上传图片

    上传图片 构造参数(NSArray *)files 上传图片—压缩 压缩到小于(...

  • iPic for Mac(图床神器) v1.7.0中文免费版

    上传图片相关设置 上传前压缩图片 可以在 iPic 的 偏好设置 中开启「上传前压缩图片」选项,目前支持压缩的图片...

  • Vue上传图片压缩的问题

    上传图片太大,需要前台进行图片压缩上传图片大于100* 1024 的用canvas 来压缩来解决然后IOS拍照上传...

  • 图片压缩上传

    参考1-HTML5实现图片压缩上传功能参考2-移动前端—图片压缩上传实践参考3-移动端H5图片压缩上传 大体步骤 ...

  • 前端学习之路——图片上传压缩

    废话不多少,直接上代码! 压缩图片函数 调用函数 图片上传与压缩 图片上传与压缩就是这么简单,欢迎大家点评指导。

  • vue 图片压缩

    vue 图片压缩 上传图片大于100* 1024 的用canvas 来压缩来解决 然后IOS拍照上传会有图片旋转的...

  • vue 图片压缩

    vue 图片压缩 上传图片大于100* 1024 的用canvas来压缩来解决 然后IOS拍照上传会有图片旋转的问...

  • h5图片上传预览压缩

    图片压缩预览上传 欢迎纠错 ~

  • 提高上传效率,iOS图片压缩总结

    最近项目中用到七牛上传图片,多张上传时,png图片大,上传极慢,特地研究了一下图片压缩的方法。 两种压缩图片的方法...

网友评论

      本文标题:vue+elementui+web上传图片压缩

      本文链接:https://www.haomeiwen.com/subject/xfijeltx.html