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'。
結果:究極妥協之后終於看到了黎明的曙光,可以正常下載所需類型的文件了,大功告成!!!