前端(JavaScript)实现图片压缩

业务场景

场景描述:前端使用标签进行上传图片时,当图片过大时,会造成接口响应速度过慢,影响用户体验。
解决方案:前端先对图片进行压缩,然后将压缩后的图片传给后端。

技术实现

我在项目里使用的是localResizeIMG(lrz)这个库,不过这个库已经很久没有维护了,介意者勿用。

  1. 基本使用localResizeIMG(lrz)

  2. localResizeIMG(lrz)插件的使用方法及属性:

lrz(file,{
    width:800,    //设置图片压缩后的最大宽度,默认为原图宽度
    height:600,    //同上
    quality:0.7,    //图片压缩质量,取值 0 - 1,默认为 0.7
    fieldName:"aijquery"    //后端接收的字段名,默认:file,一般不用这项,我们要上传数据的话,可以自定义FormData对象      
}).then(function(rst){
    rst.formData //后端可处理的数据
    rst.file     //压缩后的file对象,如果压缩率太低,将会是原始file对象
    rst.fileLen //压缩后的图片的大小,
    rst.base64     //生成后的图片base64,后端可以处理此字符串为图片,也可以直接用于 img.src = base64
    rst.base64Len     //生成后的base64的大小,后端可以通过此值来校验是否传输完整
    rst.origin //原始的file对象,里面存放了一些原始文件的信息,例如大小、日期等
}).catch(function(err){    //处理失败后执行
     
}).always(function(){    //必然执行
 
});
  1. 项目中使用情况:
    HTML部分

JS部分

后端限传1M图片,所以针对压缩比例根据不同大小的图片做了对比,如代码。

async chooseFile (e) {
      let file = e.target.files[0]
      if (file) {
        let size
        let formData = new FormData()
        if (file.type.indexOf('image') !== -1) {  // 图片压缩
          size = file.size
          let quality
          if (size > 1048576 && size < 8388608) {   // 1-8M
            quality = 0.9
          } else if (size >= 8388608 && size < 16777216) {  // 8-16M
            quality = 0.8
          } else {
            quality = 0.5
          }
          // 压缩比例每减小0.1,约等于压缩8.5倍
          await lrz(file, {
            quality: quality    // 自定义使用压缩方式
          })
            .then(function (rst) {
              // 成功时执行
              let _name = rst.origin.name
              let _type = rst.origin.type
              let _file = rst.file
              file = new window.File([_file], _name, { type: _type })
              formData.append('file', file)
            }).catch(function (e) {
              // 失败时执行
              console.log(e)
            }).always(function () {
              // 不管成功或失败,都会执行
            })
        } 
        // 界面需展示文件大小,不需要展示可删除
        size = (file.size / 1024).toFixed(2) + 'KB'
        if (size === '0.00KB') {
          // 使用的mint-ui
          Toast('不支持传空文件')
          return
        }
        // 上传的接口
        await uploadFile(formData).then(res => {
          if (res.data.success) {
            // 页面需渲染的一些东西
            id = res.data.data.fileId
            url = res.data.data.url
          } 
        }).catch(e => {
        })
        const windowURL = window.URL || window.webkitURL
        let src
        if (file.type.indexOf('image') !== -1) {
          src = windowURL.createObjectURL(file)
        }  else if (file.type.indexOf('spreadsheetml.sheet') !== -1) { // excel表
          src = require('../../assets/log/excl.png')  // 需展示的图片
        } else if (...) {
          ... // 其他类型
        }
        // 页面需渲染的数组
        this.fileArr.push({ id: id, img: src, name: file.name, size: size, url: url })
      }
    },

【注】:

  • 如果后端可以直接接收blob类型的文件,就不需要这行代码了:
new window.File([_file], _name, { type: _type })

因为这个插件是将用户选择的file类型文件转为了blob类型,接口接收的是file类型,所以自己做了个转换。

  • lrz压缩后不支持传空文件了,所以做了非空判断:
if (size === '0.00KB') {
 // 使用的mint-ui
 Toast('不支持传空文件')
 return
}
  • 需展示用户选择的图片的话:
 const windowURL = window.URL || window.webkitURL
 src = windowURL.createObjectURL(file)  // src是img标签的属性

以上就是项目中前端压缩图片上传的所有功能,希望能帮到你。

总结

实际上,插件还有很多,但是lrznpm上的weekly downloads相对比较多,还是值得一用的。
有时间了在项目中尝试使用canvas进行压缩。
脚本之家:JS和Canvas实现图片的预览压缩和上传功能
博客园:H5页面利用CANVAS压缩图片并上传

你可能感兴趣的:(前端(JavaScript)实现图片压缩)