vue 文件批量下载通用方法[streamSaver和FileSaver]

方案1. 循环url地址数组创建iframe标签

循环url地址数组创建iframe标签下载的方法,但浏览器有限制,超过10个文件将不能下载,最多下载10个。

// arr 是要下载的文件列表
 for (let i = 0; i < arr.length; i++) {
      const iframe: any = document.createElement('iframe')
      iframe.style.display = 'none' // 防止影响页面
      iframe.style.height = 0 // 防止影响页面
      iframe.src = arr[i]?.url
      document.body.appendChild(iframe) // iframe挂在到dom树上才会发请求
      setTimeout(() => {
        iframe.remove()
      }, 1000)
    }
方案2. responseType: ‘blob’ + a 标签

可解决下载数量限制问题,但是浏览器的内存非常有限,对大文件的下载,不建议此方法。

const download = (item: any) => {
  axios({
    method: 'get',
    url: item.url,
    responseType: 'blob',
    onDownloadProgress: function (e: any) {}//监控下载进度
  }).then(data => {
    const url = window.URL.createObjectURL(data.data)
    const a = document.createElement('a')
    a.download = item.original
    a.href = url
    a.click()
  })
}
const multipleSelection = ref<User[]>([])
const batchDownload = () => {
  if (multipleSelection.value?.length > 0) {
    let files = multipleSelection.value;
    files.forEach((item: any) => {
      download(item)
    })
  } else {
    ElMessage.warning('请先勾选需要下载的文件')
  }
}
方案3. file-saver 和 jszip

该插件将客户端内存存储中的文件给导出并打包.但是这插件有很大的限制就是文件大小限制,谷歌浏览器都只能2GB以下,其他更低。浏览器的内存非常有限,对大文件的下载,不建议此方法。

npm install file-saver
npm install jszip     
import { saveAs } from 'file-saver';
import JSZip from 'jszip';
import axios from 'axios';

//声明获取文件的函数
const download = (href: any) => {
  return new Promise((resolve, reject) => {
    axios({
      method: 'get',
      url: href,
      responseType: 'arraybuffer'
    }).then(data => {
      resolve(data.data)
    }).catch(error => {
      reject(error.toString())
      ElMessage.error(error.toString())
    })
  })
}

// 声明下载按钮所绑定的函数 
//multipleSelection.value 要下载的文件列表
const batchDownload = () => {
  if (multipleSelection.value?.length > 0) {
    loadLoading.value = true;
    let files = multipleSelection.value;
    let filename = '档案.zip';
    const zip = new JSZip()
    const cache = {}
    const promises: any[] = [];
    files.forEach((item:any) => {
      const promise = download(item.url).then((data:any) => {
        // 下载文件, 并存成ArrayBuffer对象
        zip.file(item.name, data, { binary: true }) // 逐个添加文件
        cache[item.name] = data //可要可不要 用来打印查检查添加了那些文件
      })
      promises.push(promise) //加到promises队列里
    })
    Promise.all(promises).then(() => {
      //异步队列全部完成时 执行下面代码
      zip.generateAsync({ type: "blob" }).then(content => {
        // 生成二进制流
        saveAs(content, filename) // 利用file-saver保存文件
        ElMessage.success('批量下载完成')
      }).finally(() => { loadLoading.value = false; })
    }).finally(() => { loadLoading.value = false; })
  } else {
    ElMessage.warning('下载的文件不能为空')
  }
}

注意:打包好的zip文件中,会自动去重 zip.file()传入的文件名参数如果相同,不会重复添加。例如如果有10个文件,其中3个重名, 那么zip文件里只有7个文件 ,不会重复打包如果想全部下载,建议文件名传入时加个index下标尾缀 例:原文件名 + ‘_’ + index

方案4. StreamSaver 解决前端下载文件的难题----最适方案

StreamSaver.js采用直接创建一个可写流到文件系统的方法。而不是将数据保存在客户端存储或内存中。解决了文件下载受浏览器内存的限制。

npm install StreamSaver   
const batchDownload = () => {
    files.forEach((item: any, index: number) => { item.name= index + 1 + '_' + item.name; })//对文件名重名处理
    let filename = `压缩包.zip`;
    const zipFileOutputStream = StreamSaver.createWriteStream(filename)
    // 创建文件列表迭代  
    const fileIterator = files.values();
    const readableZipStream = new ZIP({
      async pull(ctrl: any) {
        const fileInfo = fileIterator.next()
        if (fileInfo.done) {//迭代终止  
          ctrl.close();
        } else {
          const { original, url } = fileInfo.value;
          return fetch(url).then(res => {
            ctrl.enqueue({
              name: name,
              stream: () => res.body
            });
          })
        }
      }
    });
    if (window.WritableStream && readableZipStream.pipeTo) {
      readableZipStream.pipeTo(zipFileOutputStream)
        .then(() => ElMessage.success('批量下载完成'))
    }
}

你可能感兴趣的:(vue项目问题积累,javascript,vue.js,前端)