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 FileSaverfrom '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()) }) }) } exportconst 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'。
結果:究極妥協之後終於看到了黎明的曙光,可以正常下載所需型別的檔案了,大功告成!!!