1. 程式人生 > 實用技巧 >Vue 打包下載

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'。

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