Vue 打包下載


vue將文件/圖片批量打包下載,原理如下:

1、通過文件的url下載arraybuffer對象

2、將arraybuffer對象轉為blob

3、將blob壓縮為zip


具體操作

第一步:下載依賴:

cnpm install --save file-saver jszip

或者

npm install jszip
npm install file-saver

 

第二步,根據原理封裝成一個公共packdownload.js如下:

packdownload.js文件內容:

import axios from 'axios';
import JSZip from 'jszip'
import FileSaver from 'file-saver'


const getFile = url => {
  return new Promise((resolve, reject) => {
    axios({
      method: 'get',
      url,
      responseType: 'arraybuffer'
    }).then(data => {
      resolve(data.data)
    }).catch(error => {
      reject(error.toString())
    })
  })
}

export const handleBatchDownload = (data) => {
  //const data = ['各類地址1', '各類地址2'] // 需要下載打包的路徑, 可以是本地相對路徑, 也可以是跨域的全路徑
  const zip = new JSZip()
  const cache = {}
  const promises = []
  data.forEach(item => {
    const promise = getFile(item).then(data => { // 下載文件, 並存成ArrayBuffer對象
      const arr_name = item.split("/")
      const file_name = arr_name[arr_name.length - 1] // 獲取文件名
      zip.file(file_name, data, { binary: true }) // 逐個添加文件
      cache[file_name] = data
    })
    promises.push(promise)
  })
  Promise.all(promises).then(() => {
    zip.generateAsync({ type: "blob" }).then(content => { // 生成二進制流
      FileSaver.saveAs(content, "打包下載.zip") // 利用file-saver保存文件
    })
  })
}

第三步,在需要的文件中使用

首先,先進行引用

import { handleBatchDownload } from '@/utils/packdownload'

然后,使用

 如圖所示,參數就是下載地址數組,使用很簡單


跨域

雖然說通過以上操作完成了批量打包下載,但是卻會出現跨域的情況。。因為我的文件是在阿里雲服務器上的,不在同一域名下。網上有個關於文件下載跨域的解決方法的博客,記錄了前端解決跨域的方式,有些方式我之前也嘗試過,呵呵,最終還是需要后端協助。。

第一次嘗試:

通過xhr請求獲取文件,然后下載到本地,代碼如下:

// 下載按鈕點擊事件
fileDownload() {
    let url = this.data.url; // data:項目中獲取的數據,包含文件url以及文件名等相關參數
    let fileName = this.data.file_name;
    let xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';
    xhr.onload = (e) => {
        const res = e.target.response;
        this.saveAs(res, fileName);
    };
    xhr.send();
}
 
// 導出文件函數
saveAs (obj, fileName) {
    let ele = document.createElement('a');
    ele.download = fileName || '下載';
    ele.href = URL.createObjectURL(obj); // 綁定a標簽
    ele.style.display = 'none';
    document.body.appendChild(ele); // 兼容火狐瀏覽器
    ele.click();
    setTimeout(function () { // 延時釋放
        URL.revokeObjectURL(obj); // 用URL.revokeObjectURL()來釋放這個object URL
        document.body.removeChild(ele);// 兼容火狐瀏覽器
    }, 100);
};

結果:文件可以直接下載,but為蝦米有的文件可以下載、有的文件告訴我跨域問題???刷新頁面之后,剛剛還可以下載的文件又不可以下載了!!!崩潰ing...聯系運維的老哥嘗試修改一下第三方服務器的參數,發現沒有卵用,只能再嘗試一下了。

第二次嘗試:(jsonp)

既然是跨域的問題,網上的解決方案蠻多的,而且作為前端面試必考題,我背的也蠻熟的。首先使用jsonp來解決,步驟如下:

1、安裝jsonp插件

npm install jsonp --save

2、在代碼中使用jsonp

import jsonp from 'jsonp'; // 導入插件
 
// 下載按鈕點擊事件
fileDownload () {
    let url = this.data.url; // data:項目中獲取的數據,包含文件url以及文件名等相關參數
    let fileName = this.data.file_name;
    // 先測試一下能不能跨域成功
    jsonp(url, null, (err, data) => {
        if (err) {
            console.error(err.message);
        } else {
            console.log(data);
        }
    })
}

結果:可能是哪里使用不對,反正是沒有請求數據成功,還是顯示跨域問題,既然不行,那就再換方法。

3、卸載jsonp插件

npm uninstall jsonp

第三次嘗試:(fetch跨域)

廢話不多說,直接上代碼: 

// 下載按鈕點擊事件
fileDownload () {
    let url = this.data.url; // data:項目中獲取的數據,包含文件url以及文件名等相關參數
    let fileName = this.data.file_name;
    // 先測試一下能不能跨域成功
    let myHeaders = new Headers({
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'text/plain'
    });
    fetch(url, {
        method:'GET',
        headers:myHeaders,
        mode:'cors'
    }).then(res=>{
        console.log(res);
    });
}

結果:依然沒有解決跨域的問題,革命尚未成功,老子還得努力啊。(ps: fetch的mode屬性設置為’no-cors‘的時候能請求成功,但是返回值無法使用,木的辦法)

第四次嘗試:(使用插件downloadjs下載文件)

1、安裝downloadjs插件

npm install downloadjs --save

2、使用downloadjs插件

import download from 'downloadjs'; // 引用插件
 
// 下載按鈕點擊事件
fileDownload () {
    let url = this.data.url; // data:項目中獲取的數據,包含文件url以及文件名等相關參數
    download(url); // 沒看錯,就是這么簡單
}

結果:我在自己的電腦上發現完全可以下載文件,沾沾自喜了大概十分鍾,通過別人的電腦訪問我的IP測試,發現有的完全沒問題,有的還是出現跨域的問題。。。。。。。。。。。要瘋了有木有。。。。。。。。接着改吧。。。。。。。

3、卸載downloadjs插件

npm uninstall downloadjs

第五次嘗試:(前端已經盡力了,讓后端大佬幫忙吧)

在使用了好多方法之后,在歷時一整天的嘗試之后,我,決定放下前端的驕傲,找后端大佬(.net)商量一下,決定后端先將第三方服務器上的文件轉換成二進制文件,然后通過一個接口返回給前端處理,上代碼:

// 下載按鈕點擊事件
async fileDownload () {
    let url = this.data.url; // data:項目中獲取的數據,包含文件url以及文件名等相關參數
    let fileName = this.data.file_name;
    const res = await getFile({ // 獲取文件二進制數據的接口
        oss_url: url
    });
    this.saveAs(new Blob([res], { type: 'text/plain;charset=UTF-8' }), fileName);
}
 
// 導出文件函數
saveAs (obj, fileName) {
    let ele = document.createElement('a');
    ele.download = fileName || '下載';
    ele.href = URL.createObjectURL(obj); // 綁定a標簽
    ele.style.display = 'none';
    document.body.appendChild(ele); // 兼容火狐瀏覽器
    ele.click();
    setTimeout(function () { // 延時釋放
        URL.revokeObjectURL(obj); // 用URL.revokeObjectURL()來釋放這個object URL
        document.body.removeChild(ele);// 兼容火狐瀏覽器
    }, 100);
};

PS:  (1).將二進制流轉為Blob類型的時候,屬性:{type: 'text/plain;charset=UTF-8'};

        (2).獲取二進制文件的接口,我是使用項目里封裝的axios方法,需注意設置屬性:responseType: 'blob'。

結果:究極妥協之后終於看到了黎明的曙光,可以正常下載所需類型的文件了,大功告成!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM