先說下網上給的解答方案:
1、npm i jszip file-saver (axios) ----axios一般第一次請求的時候就下載過了,如果沒有,這里下載的時候加上axios
2、引入這3個插件
import axios from 'axios' import JSZip from 'jszip' import FileSaver from 'file-saver'
3、定義getFile()函數,如果是這種格式的定義函數,寫在export default {} 的上面
const getFile = url => { return new Promise((resolve, reject) => { let obj = { method: 'get', url, // responseType: 'blob' responseType:'arraybuffer' } axios(obj) .then(data => { resolve(data.data) }) .catch(error => { reject(error.toString()) }) }) }
4、利用jszip將文件挨個寫入壓縮包文件中
export default { methods: { handleDownload() { const data1 = [ 'https://test-cloud-hospital-front.rubikstack.com/ms-hoc-material/v3/file/download/d1c8bc44c0f34f2f80778ad7a5222cfc.jpeg', // 'https://test-cloud-hospital-front.rubikstack.com/ms-hoc-material/v3/file/download/e9c12f0c8ae54ea8aa1e5de29a454b30.pdf', // 'https://test-cloud-hospital-front.rubikstack.com/ms-hoc-material/v3/file/download/0f7c01f52635460e9bb1de1a31fbda44.pdf', // 'https://test-cloud-hospital-front.rubikstack.com/ms-hoc-material/v3/file/download/851063dd3bf54219b6e6a03046f824ed.pdf' ] const zip = new JSZip() const cache = {} const promises = [] data1.forEach(item => { const promise = getFile(item).then(data => { const arr_name = item.split('/') // 下載文件, 並存成ArrayBuffer對象 const file_name = arr_name[arr_name.length - 1] // 獲取文件名 zip.file(file_name, data, { binary: true }) // 逐個添加文件 cache[file_name] = data console.log(cache) }) promises.push(promise) }) Promise.all(promises).then(() => { zip.generateAsync({ type: 'blob' }).then(content => { console.log(content) // 生成二進制流 FileSaver.saveAs(content, '文件下載.zip') // 利用file-saver保存文件 自定義文件名 }) }) } } }
接下來說下我自己的用法:
先封裝個組件再說,組件關系如下:
Download.vue組件的完整代碼:
<template> <el-button @click="handleDownload">一鍵下載</el-button> </template> <script> import axios from 'axios' import JSZip from 'jszip' import FileSaver from 'file-saver' export default { data() { return { fileList: [] } }, created() { this.$observer.$on('downloadFileList', fileList => { console.log(fileList) this.fileList = fileList }) }, methods: { handleDownload() { const zip = new JSZip() const cache = {} const promises = [] this.fileList.forEach(item => { const promise = this.getFile(item.fileUrl).then(data => { const file_name = item.fileName 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保存文件 自定義文件名 saveAs(content, '文件下載.zip') // 利用file-saver保存文件 自定義文件名 }) }) }, getFile(url) { return new Promise((resolve, reject) => { axios({ method: 'get', url, responseType: 'blob' // responseType: 'arraybuffer' }) .then(data => { console.log(data) resolve(data.data) }) .catch(error => { reject(error.toString()) }) }) } } } </script>
說說踩得坑:
一開始我通過axios去請求的時候,then()函數里返回的是
data.data是一段二進制流字符串,這會導致下載下來的文件打不開,或者打開就是個空白,因為數據類型都是錯的(應該返回的data.data是Blob類型的)。
然后就開始了操蛋的找坑之路,各種百度,各種調試, 前端后端一起找原因,差點把我心態搞崩了。。。
快要放棄的時候,准備直接用后端寫的接口下載的時候,看到了這句話:mock模塊會影響原生的ajax請求,使得服務器返回的blob類型變成亂碼
mock初始化的時候給攔截響應設置了responseType:'' 這,這,這…跟誰講道理去
就算用原生也是不行:
var zip = new JSZip() var eleLink var url = 'https://test-cloud-hospital-front.rubikstack.com/ms-hoc-material/v3/file/download/28b9af6a53154a02971ac6a4efebcd10.pdf' var xhr = new XMLHttpRequest() xhr.open('get', url, true) xhr.send() xhr.responseType = 'blob' // 返回類型blob xhr.onload = function() { if (this.status === 200) { console.log(this,this.response) let blob = new Blob([this.response]) zip.file('smile.pdf', blob) zip.generateAsync({ type: 'blob' }).then(function(content) { saveAs(content, 'example.zip') }) } }
於是,我在main.js中將這個小B崽子注釋掉了:
然后數據就對了:
OK!可以下載了!
問題:
1、responseType 設置blob和arraybuffer都可以下載:
有知道的大佬可以給我留言
2、FileSaver.saveAs(content, '文件下載.zip') 可以寫成saveAs(content, '文件下載.zip'),這是不是就是說file-saver這個包是沒用的,但是網上怎么都是jszip+file-saver的教程,知道的大佬麻煩留言~
3、axios的封裝,最好是封裝出一個axios的實例,然后對這個實例進行操作