[TOC]
>[success] # 下載文件功能
<br/>
[參考文檔:關于前端實現文件下載功能](https://segmentfault.com/a/1190000019359452#item-1)
[參考文檔:前端文件下載的正確打開方式](https://mp.weixin.qq.com/s/eHeQI-nJ2tNq6AmTmhLLnw)
文件下載方式有`3種方式`和`批量下載并且打包`:
1. window.open()
2. 通過a標簽打開新頁面下載
3. 通過文件流(blob)的方式下載
4. 如何實現批量下載打包
<br/>
>[success] ## window.open()打開新頁面下載文件
<br/>
~~~
使用場景:下載'excel'文件,后端提供接口,接口返回的是'文件流',可以直接使用'window.open()',最簡單
的方式。
優點:最簡潔。
弊端:當'參數錯誤'時,或其它原因導致接口'請求失敗',這時'無法監聽到接口返回的錯誤信息',需要保證請求
必須是正確的且能正確返回'數據流',不然打開新頁面會'直接輸出接口返回的錯誤信息',體驗不好。
~~~
<br/>
1. index.html
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>下載文件</title>
<script>
window.onload = function () {
document.querySelector('button').onclick = function () {
const URL = 'download.io' // 接口
window.open(URL, '文件名')
}
}
</script>
</head>
<body>
<button>下載文件</button>
</body>
</html>
~~~
<br/>
>[success] ## a標簽打開新頁面下載文件
<br/>
~~~
通過'a標簽'下載的方式,同'window.open()'是一樣的,唯一的優點是可以'自定義下載后的文件名','a標簽'
里有'download屬性可以自定義文件名',如果不指定,那么下載的文件名就會根據請求內容的 'Content-Disposition' 來確定,如果沒有 'Content-Disposition' ,那么就會使用請求的 'URL' 的 '最后一部分作為文件名'。
弊端:同window.open()方式一樣,無法監聽錯誤信息。
問題:以上'兩種方式',當在下載'.mp3格式',或者'視頻文件'時,瀏覽器會'直接播放該文件',而達不到直接
'下載'的功能,此時,'當下載音視頻文件時無法使用這兩種方式'。
~~~
<br/>
1. index.html
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>下載文件</title>
<script>
window.onload = function () {
document.querySelector('button').onclick = function () {
const URL = 'download.io' // 接口
/**
* a標簽下載文件方法
* @param { String } url 接口url
* @param { String } option 文件要更改的名稱
*/
const exportFile = (url, fileName) => {
// 創建a標簽
const link = document.createElement('a')
// 獲取body元素
const body = document.querySelector('body')
// 設置url下載鏈接(接口)
link.href = URL
// 重命名文件名稱(這個屬于html5新特性,有些瀏覽器暫時不支持,而且跨域重命名會失效)
link.download = fileName
// 隱藏標簽
link.style.display = 'none'
// 把標簽添加到body元素最后面
body.appendChild(link)
// 點擊a標簽
link.click()
// 銷毀a標簽
body.removeChild(link)
}
// 執行下載文件方法
exportFile(URL,'奧利給')
}
}
</script>
</head>
<body>
<button>下載文件</button>
</body>
</html>
~~~
<br/>
>[success] ## 通過文件流的方式下載
<br/>
~~~
為了方便'重復使用下載功能',進行了一個簡單的封裝,思路:
1. 調用'下載接口',指定返回'數據類型blob'
2. 在'ajax攔截器'時候進行'類型判斷'如果為'媒體類型'就執行保存文件方法。
~~~
<br/>
1. responseType的幾種值類型
<br/>

<br/>
2. index.html
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="test.js"></script>
<title>下載文件</title>
<script>
window.onload = function () {
document.querySelector('button').onclick = function () {
// 下載接口
const URL = 'download.io'
// 調用下載接口
ajax({
url: URL,
type: 'get',
responseType: 'blob' // 設置返回的數據類型blob、
})
}
}
</script>
</head>
<body>
<button>下載文件</button>
</body>
</html>
~~~
<br/>
3. test.js
~~~
/**
* 保存文件方法
* @param { Object } blob blob二進制大對象
* @param { Object } filename 文件名稱
*/
const saveAs = (blob, filename) => {
if (window.navigator.msSaveOrOpenBlob) {
// Navigator.msSaveBlob()方法將“ File或” 保存Blob到磁盤。
navigator.msSaveBlob(blob, decodeURI(filename))
} else {
// 創建a標簽
const link = document.createElement('a')
// 獲取body
const body = document.querySelector('body')
// 創建對象url
link.href = window.URL.createObjectURL(blob)
// 重命名文件名稱
link.download = decodeURI(filename)
// 隱藏a標簽
link.style.display = 'none'
// 把a標簽添加到body后面
body.appendChild(link)
// 模擬點擊a標簽
link.click()
// 刪除a標簽
body.removeChild(link)
// 用來釋放一個之前已經存在的、通過調用 URL.createObjectURL() 創建的 URL 對象
window.URL.revokeObjectURL(link.href)
}
}
/**
* ajax工具函數
* @param { Object } option 該參數為對象,以下為參數說明
* @param { String } data 接口參數
* @param { String } type 請求類型 post/get
* @param { String } url 接口url
* @param { String } responseType 數據返回類型blob、arrayBuffer等等
* @param { Function } success 數據成功的回調函數
*/
function ajax (option) {
var xhr = new XMLHttpRequest();
// 如果是get,并且有參數才設置
if (option.type === 'get' && option.data) {
option.url += "?";
option.url += option.data;
option.data = null; // 這樣最后直接send data即可
}
xhr.open(option.type, option.url);
// 返回指定數據類型blob、arrayBuffer等等
xhr.responseType = option.responseType || ''
// 這里是設置請求頭的授權密鑰
xhr.setRequestHeader('authorization', 'xxxxxxxxxxxx') // 這里根據項目需求而定是否添加
// 如果是post,并且有參數才設置
if (option.type == 'post' && option.data) {
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
}
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var type = xhr.getResponseHeader("Content-Type"); // 獲取服務器在header上的信息
if (type.indexOf('json') != -1) { // 判斷為json格式信息
option.success(JSON.parse(xhr.responseText))
} else if (type.indexOf('xml') != -1) { // 判斷為xml格式信息
option.success(xhr.responseXML)
} else if(type.indexOf('octet-stream') != -1){ // 判斷為媒體類型格式
// 獲取文件名稱
let [,filename] = xhr.getResponseHeader('Content-Disposition').split('=');
// 執行保存文件方法
saveAs(xhr.response, filename)
} else { // 普通字符串
option.success(xhr.responseText)
}
}
}
xhr.send(option.data);
}
~~~
<br/>
>[success] ## 如何實現批量下載,且打包文件
<br/>
1. index.html
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- jszip -->
<script src="https://cdn.bootcss.com/jszip/3.2.2/jszip.min.js"></script>
<!-- FileSaver.js -->
<script src="https://cdn.bootcss.com/FileSaver.js/1.3.8/FileSaver.min.js"></script>
<!-- ajax.js -->
<script src="ajax.js"></script>
<title>下載文件</title>
<script>
window.onload = function () {
document.querySelector('button').onclick = function () { // 點擊下載按鈕
let urlArr = [ // 批量選中的文件Url數組
{
url: 'download.io',
fileName: '文件1.xlsx'
},
{
url: 'download.io',
fileName: '文件2.xlsx'
}
]
/**
* 批量下載并且打成zip包
* @param urlArr Array [{url: 下載文件的路徑, fileName: 下載文件名稱}]
* @param filename zip文件名
*/
const download = (urlArr, filename = '默認zip文件名') => {
// urlArr沒有值就返回
if (!urlArr.length) return
// new一個壓縮構造函數
const zip = new JSZip()
// 儲存多個請求
const promisesArr = []
// 調用批量下載接口
Promise.all(urlArr.map(item => ajax({
url: item.url,
type: 'get',
responseType: 'blob'
}))).then((res) => {
for(let i=0;i<urlArr.length;i++){
zip.file(urlArr[i].fileName, res[i], { binary: true }) // 逐個添加文件
}
zip.generateAsync({ type: 'blob' }).then((content) => { // 生成二進制流
saveAs(content, `${filename}.zip`) // 利用file-saver保存文件
})
})
}
// 執行批量下載并且打壓縮包
download(urlArr, '我要打個壓縮包')
}
}
</script>
</head>
<body>
<button>下載文件</button>
</body>
</html>
~~~
2. ajax.js
~~~
/**
* ajax工具函數
* @param { Object } option 該參數為對象,以下為參數說明
* @param { String } data 接口參數
* @param { String } type 請求類型 post/get
* @param { String } url 接口url
* @param { String } responseType 數據返回類型blob、arrayBuffer等等
* @param { Function } success 數據成功的回調函數
*/
function ajax (option) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
// 如果是get,并且有參數才設置
if (option.type === 'get' && option.data) {
option.url += "?";
option.url += option.data;
option.data = null; // 這樣最后直接send data即可
}
xhr.open(option.type, option.url);
// 返回指定數據類型blob、arrayBuffer等等
xhr.responseType = option.responseType || ''
// 這里是設置請求頭的授權密鑰
xhr.setRequestHeader('authorization', 'xxxxxxx') // 這里根據需求而定是否添加
// 如果是post,并且有參數才設置
if (option.type == 'post' && option.data) {
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
}
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var type = xhr.getResponseHeader("Content-Type"); // 獲取服務器在header上的信息
if (type.indexOf('json') != -1) { // 判斷為json格式信息
option.success(JSON.parse(xhr.responseText))
} else if (type.indexOf('xml') != -1) { // 判斷為xml格式信息
option.success(xhr.responseXML)
} else if(type.indexOf('octet-stream') != -1){ // 判斷為媒體類型格式
resolve(xhr.response)
} else { // 普通字符串
option.success(xhr.responseText)
}
}
}
xhr.send(option.data);
})
}
~~~
- 基本概念
- 服務器
- PHP學習
- PHP根據數據生成頁面
- form表單提交數據到服務器
- form表單查詢信息詳情頁
- 列表渲染展示以及跳轉詳情
- PHP拆分寫法
- form表單提交
- get方式提交數據補充
- post方式提交數據
- post上傳文件
- 請求報文和響應報文基本概念
- XMLHTTPRequest對象的基本使用
- 回調函數&獲取返回的數據
- ajax發送get請求
- ajax驗證用戶是否存在邏輯
- ajax發送post請求
- 新浪云使用方法
- onload 和 onreadystatechange
- XML格式
- 服務器返回XML格式數據
- JSON格式
- 服務器返回JSON格式數據
- ajax工具函數封裝
- js模板引擎
- 跨域解決方案
- JSONP
- CORS解決跨域
- 下載文件功能