zoukankan      html  css  js  c++  java
  • 前端实现批量打包下载文件

    需求说明:

      后端接口返回附件列表(含URL),这些附件存在阿里云OSS上。一期需求是实现对列出的附件进行点击下载,也就是每次只下载点击的附件(PDF | 图片),使用一段时间后制定二期需求时,增加批量下载功能,需要打包在一起。附言:本文所写都是纯前端实现,后端接口只需要返回路径即可。

    单独下载图片:

      直接使用<a>标签,会存在这样的问题:同源链接点击后直接在浏览器打开,通过在<a>标签内指定download属性可以避免,但是非同源链接却不行。所以通过Canvas + JS方式实现点击图片直接下载,这里要解决这么几个问题:1、非同源及跨域问题;2、Canvas图片下载限制问题。同源问题很好解决,只需要一行代码:

    image.setAttribute('crossOrigin', 'anonymous')

    为了解决Canvas图片像素大小的限制,转为blod流数据,下面附上代码:

      /**
       * @param {Number} imgsrc 图片路径
       * @param {Number} name 自定义图片名称
       * 直接使用canvas下载有图片像素大小的限制,所以转成blod流下载
       **/
      downloadIamge (imgsrc, name) { // 下载图片地址和图片名
        let image = new Image()
        // 解决跨域 Canvas 污染问题
        image.setAttribute('crossOrigin', 'anonymous')
        let fun = this.dataURLtoBlob
        image.onload = function () {
          let canvas = document.createElement('canvas') // 创建Canvas
          canvas.width = image.width
          canvas.height = image.height
          let context = canvas.getContext('2d')
          context.drawImage(image, 0, 0, image.width, image.height) // Canvas画图
          let url = canvas.toDataURL({format: 'png', multiplier: 4}) // 通过toDataURL()方法将图像转为url
          var blob = fun(url)
          var objurl = URL.createObjectURL(blob) // 转成blod
          let a = document.createElement('a') // 生成一个a元素
          let event = new MouseEvent('click') // 创建一个单击事件
          a.download = name || "'photo" // 设置图片名称
          a.href = objurl // 将生成的URL设置为a.href属性
          a.dispatchEvent(event) // 触发a的单击事件
        }
        image.src = imgsrc + '?=' + Math.random() // 加入随机数 解决跨域不能下载问题
      },
    
      /**
       * @param {string} dataurl 图像地址
       * 转blod流
       */
      dataURLtoBlob (dataurl) {
        let arr = dataurl.split(',')
        let mime = arr[0].match(/:(.*?);/)[1]
        let bstr = atob(arr[1])
        let n = bstr.length
        let u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n)
        }
        return new Blob([u8arr], {type: mime})
      }

    在实现的时候,如果这样指定image的src属性:

    image.src = imgsrc 

    在运行之后,发现并没有解决非同源图片直接打开的问题,所以在下载地址后加了随机数

    image.src = imgsrc + '?=' + Math.random()

    打包批量下载:

      这里使用了其他的包:JSZip(用于文件打包)和 file-saver(用于下载),因为是在Vue项目中使用,直接在项目中下载

    npm install jszip
    npm install file-saver

     在需要使用的文件中引入:

    import JSZip from "jszip";
    import FileSaver from "file-saver";

    下载主方法代码如下:

      // <button @click="down">批量下载</button>
        async down() {
          try {
            let zip = new JSZip();
            for (let i = 0; i < this.arr.length; i++) {
              let lst = this.arr[i].split(".");
              let fileType = lst[lst.length - 1];
              if (fileType.toLocaleUpperCase() === "PDF") {
                await this.getFile(this.arr[i]).then(pdf => {
                  zip.file("HelloPDF.pdf", pdf, { binary: true });
                });
              } else {
                await this.getBase64Image(this.arr[i]).then(res => {
                  zip.file("HelloIMG" + i + "." + fileType, res, { base64: true });
                });
              }
            }
            this.downImg(zip);
          } catch (err) {
            console.log("err", err);
          }
        },

    这里使用了async/await来进行文件异步操作,确保zip填充操作执行完之后,才执行zip的下载。

    downImg(zip) {
      zip
        .generateAsync({
          type: "blob"
        })
        .then(content => {
          let fileName = "批量下载.zip";
          FileSaver.saveAs(content, fileName);
        });
    },
    //****传入图片链接,返回base64数据
    getBase64Image(url) {
      return new Promise((resolve, reject) => {
        var base64 = "";
        var img = new Image();
        img.setAttribute("crossOrigin", "Anonymous");
        img.onload = () => {
          base64 = this.image2Base64(img);
          resolve(base64.split(",")[1]);
        };
        img.onerror = () => reject("加载失败");
      // 这里可能会有跨域失败的问题,解决方案同上,url + 随机数 img.src
    = url; }); }, image2Base64(img) { var canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, img.width, img.height); var dataURL = canvas.toDataURL("image/png"); return dataURL; }, //****传入文件链接,返回arraybuffer数据 getFile(url) { return new Promise((resolve, reject) => {
      // 这里的$http是Vue里的axios
    this.$http({ method: "get", url, responseType: "arraybuffer" }) .then(data => { resolve(data.data); }) .catch(error => { reject("PDF加载失败:" + error); }); }); },

    以上,实现方式记录。

     
    好好学习,认真笔记
  • 相关阅读:
    JQuery常用函数方法全集
    从零开始学习jQuery (三) 管理jQuery包装集
    Jquery选择器总结
    oracle常用函数总结
    普通Java类获取Spring的Bean的方法
    AtCoder Beginner Contest 173 A
    HDU 5974 A Simple Math Problem
    Codeforces Round #655 (Div. 2) B. Omkar and Last Class of Math
    Codeforces Round #655 (Div. 2) A. Omkar and Completion
    SWPU信息学院团体程序设计竞赛题解
  • 原文地址:https://www.cnblogs.com/xuanyuandai/p/13628089.html
Copyright © 2011-2022 走看看