图片压缩与文件下载、上传

1,170 阅读4分钟

一.文件下载

1. 前后端分离项目:实现文件导出,导出格式为.txt文件,console.log(res)看到的是返回文件的内容,前端用以下方法可实现文件下载。

const handleIndividual = () => {
   // taskCode 变量
   axios.post('请求地址', {需要传递的数据}, {responseType: 'blob'}).then(res => {
       // 创建blob对象
       const blob = new Blob([res])
       // 下载文件命名
       const fileName = '自定义.txt';
        // 非IE下载
        // 判断a标签中是否存在download属性
       if ('download' in document.createElement('a')) {
           // 创建a标签
           const elink = document.createElement('a')
           // 将下载的文件 文件名赋值
           elink.download = fileName
           elink.style.display = 'none'
           elink.href = URL.createObjectURL(blob)
           // 想body中添加a标签
           document.body.appendChild(elink)
           elink.click()
           // 释放URL 对象
           URL.revokeObjectURL(elink.href) 
           // body中移除a标签
           document.body.removeChild(elink)
       } else { // IE10+下载
           navigator.msSaveBlob(blob, fileName)
       }
   })
}

2. 前端单独实现导出: 首先进行安装,以下为两种安装方式:

yarn add js-export-excel
npm install js-export-excel
import ExportJsonExcel from "js-export-excel";
casHoutUpload = () => {
  const { dataSource } = this.state;       //表格数据
  let option = {};
  let dataTable = [];
  if (dataSource) {
      for (let i in dataSource) {
          if (dataSource.length !== 0) {
              // 表示表格表头对应的数据 
              let obj = {
                  "商户编号": dataSource[i].mno,
                  '商户中文名称': dataSource[i].mnoNm,
                  '商户英文名称': dataSource[i].mnoNmEn,
                  '产品分类': dataSource[i].productTypeTr,
                  '产品名称': dataSource[i].productName,
                  '产品开通时间': dataSource[i].productOpenTime,
                  '生效计费数': dataSource[i].effectCount,
                  '待生效计费数': dataSource[i].toEffectCount,
                  '待审核计费数': dataSource[i].toAudEffectCount,
              };
              dataTable.push(obj);
          }
      }
  }
  // 设置导出文件名
  option.fileName = '商户计费配置-查询';       
  option.datas = [{
      sheetData: dataTable,
      sheetName: 'sheet',
      sheetFilter: ['商户编号', '商户中文名称', '商户英文名称', '产品分类', '产品名称', '产品开通时间', '生效计费数', '待生效计费数', '待审核计费数'],
      sheetHeader: ['商户编号', '商户中文名称', '商户英文名称', '产品分类', '产品名称', '产品开通时间', '生效计费数', '待生效计费数', '待审核计费数'],
  }];
  let toExcel = new ExportJsonExcel(option);
  toExcel.saveExcel();
};

二. 文件上传

1. 在react框架中使用antd中的组件中的Upload 组件可进行上传,可参考antd官网。

2. 使用formData进行上传文件

// 创建FormData对象
var formData = new FormData();
// 通过form表单拿到对应的文件file以及其他需要传递给后端的数据data 
// 将需要进行传给后端的值添加在FormData对象中
// "dataName" 为后端需要接受值的名字,data为前端传输的值
formData.append("dataName",data)
formData.append("fileName",file)
// 调接口处理
...

formData提供了一种表示表单数据的键值对的构造方式,经过它的数据可以使用 XMLHttpRequest.send() 方法送出,本接口和此方法都相当简单直接。所以formData对象可以进行文件传输。

三. 图片拖拽展示

图片拖拽

首先创建一个.html文件,写入一下代码:

  <div id="dropbox" style="width: 300px; height: 200px;">拖放</div>
  <script>
    // 通过ID找到对应的元素
    var dropbox = document.getElementById("dropbox");
    // 添加事件
    dropbox.addEventListener("dragenter", dragenter, false);
    dropbox.addEventListener("dragover", dragover, false);
    dropbox.addEventListener("drop", drop, false);

    // 当拖动的元素或被选择的文本进入有效的放置目标时触发
    function dragenter(e) {
        e.stopPropagation();
        e.preventDefault();
    }
    // 当元素或者选择的文本被拖拽到一个有效的放置目标 上 时触发
    function dragover(e) {
        e.stopPropagation();
        e.preventDefault();
    }
    // 拖动过程中释放鼠标键时触发
    function drop(e) {
        e.stopPropagation();
        e.preventDefault();
        var dt = e.dataTransfer;
        var files = dt.files;
        handleFiles(files);
    }
    function handleFiles(files){
    	  // 在此处可以获取文件信息 说明拖拽效果已经实现
        console.log(files)
    }
  </script>

展示拖拽图片

重写handleFiles方法:

 function handleFiles(files) {
       // 由于可一次拖拽多个图片 所以此处使用for循环处理
       for (var i = 0; i < files.length; i++) {
           var file = files[i];
           // 判断是否为图片
           var imageType = /^image\//;
           if (!imageType.test(file.type)) {
               continue;
           }
           // 创建img标签
           var img = document.createElement("img");
           // 添加样式名称
           img.classList.add("obj");
           // 添加file属性
           img.file = file;
           // 查找元素
           var preview = document.getElementById('dropbox');
           // 将创建的标签添加到preview中
           preview.appendChild(img);
           // 请看下面说明
           var reader = new FileReader();
           reader.onload = (function (aImg) {
               return function (e) {
                   aImg.src = e.target.result;
               };
           })(img);
           reader.readAsDataURL(file);
       }
   }
说明: 创建了FileReader来处理异步的图片加载并把他赋给img元素。具体说明如下:
      在创建一个新的 FileReader对象后,我们新建了它的onload 函数,
      然后调用readAsDataURL()函数开始后台读取文件。
      当整个图片文件的内容都被全部加载完后,它们被转换成了一个被传递到onload回调函数的data:URL。
      我们再执行常规操作将img元素的src属性设置为刚刚加载完毕的URL,
      使得图像可以显示在用户屏幕上的缩略图中。

注意: 上面例子中并没有对添加的样式名称添加任何样式,如有特定要求,可自行添加

实现效果如下图:

四. 图片压缩上传

图片压缩展示

首先我们看一下是不是想要这样的效果图呢

实现思想:简而言之 -- canvas绘图

  • 首先获取文件资源
  • 判断是否为图片
  • 判断图片大小,如果大于你设定的要求,则进行压缩
  • 读取文件,转换为img标签元素
  • 使用canvas压缩(canvas: 是一个可以使用脚本(通常为JavaScript)来绘制图形的 HTML 元素.)
  • 转换为URL

在上面的例子中可以看到通过handleFiles方法可以获得文件,文件信息如下: (注意:与后面作对比)

function handleFiles(files, callback=()=>{}){
	console.log(files);   // 1. 文件资源
    for (var i = 0; i < files.length; i++) {
    	// 2. 判断是否为图片
        // 如果对图片格式有严格要求 可具体进行判断
        let file = files[i];
        let imageType = /^image\//;
        if (!imageType.test(file.type)) {
            continue;
        }
        // 3. 本例中不进行图片大小的限制 如需要时添加下面的代码
    
    	// 判断图片大小
        // 可根据需求更改大小限制
    	// if(files[i].size /1024/1024 > 3){  
        	// 压缩代码
        // }
        
        // 4. 读取文件,转换为img标签元素
        let reader = new FileReader();
        reader.onload = ((e) => {
                const quality = 0.1; // 压缩质量
                const type = "image/jpeg";
                const img = document.createElement('img');
                let preview = document.getElementById('dropbox');
                img.src = e.target.result; // base64
                img.onload = () => {
                    const canvas = document.createElement('canvas'); // 创建画布
                    const ctx = canvas.getContext('2d');
                    const cvWidth = img.width * 0.5 ;
                    const cvHeight = img.height * 0.5 ;
                    // 设置宽高
                    canvas.height = cvHeight;
                    canvas.width = cvWidth;
                    ctx.clearRect(0, 0, cvWidth, cvHeight);
                    // 将img绘制到画布上
                    ctx.drawImage(img, 0, 0, cvWidth, cvHeight)
                    // 5. 使用toDataURL转换为URL(base64)
                    let url = canvas.toDataURL(type, quality);
                    callback(url)
                }
                preview.appendChild(img)
            })
            reader.readAsDataURL(file);
    }
}

// 展示
// 拖动过程中释放鼠标键时触发
function drop(e) {
    e.stopPropagation();
    e.preventDefault();
    var dt = e.dataTransfer;
    var files = dt.files;
    handleFiles(files, (url) => {
    	console.log(url, 'url')  // 请看下面图片
    	const img1 = document.createElement('img');
        img1.src = url;
        let preview = document.getElementById('dropbox');
        preview.append(img1)
    });
}

我们在handleFiles方法中使用了toDataURL方法,拿到URL的值为:

图片压缩上传

前面我们已经完成了图片压缩并展示,对于上传我们只需要更改一下代码注释中的第五步即可

 // 5. 使用toDataURL转换为Blob对象
 function handleFiles(){
    ...
    canvas.toBlob(
      blob => {
          const file = new window.File([blob], name, { type: type });
          callback(file);
      },
      type,
      quality
    );
 }
 
function drop(e) {
    e.stopPropagation();
    e.preventDefault();
    var dt = e.dataTransfer;
    var files = dt.files;
    handleFiles(files, (url) => {
    	console.log(url, 'url')  // 请看下面图片
    	// 此处可使用 本文章的 文件上传 中的 2
    });
}

这时我们在drop方法中获得的URL为一份文件对象,则可以拿到压缩的文件对象后调用接口进行上传:

总结

我们可以通过这个图片中的size与上面压缩前的文件信息进行对比可以发现size变小了,从而实现了压缩的效果。图片压缩后可进行上传与展示,只需要将绘制好的画布通过使用toBlob(文件对象)和toDataURL(URL base64)方法进行转换即可。在压缩图片的方法中,图片的宽高压缩比例、质量压缩比例都可进行修改,根据需求而定。

最后

如果选择粘贴文中的代码,记得检查一下大小写,由于书写时需要测试准确性,可能对于符号的大小写区分不准确,防止功能正常实现。

biu biu biu ~ ❤️❤️❤️❤️ 点关注 🙈🙈 不迷路