[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/>
![](https://img.kancloud.cn/2e/2e/2e2ea00a71c6752c868afb9f263c09ab_1032x553.png)
<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解决跨域
- 下载文件功能