文件下载
文件下载一般分为两种场景:
- 返回的资源链接地址
- 不用考虑资源大小问题
- 接口返回文件流
一、针对返回有明确资源地址的场景
1. form 表单提交
- 为下载按钮添加 click 事件,点击时动态生成一个表单,利用表单提交的功能来实现文件的下载js
/** * 下载文件 * @param {String} path - 请求的地址 * @param {String} fileName - 文件名 */ function downloadFile (downloadUrl, fileName) { // 创建表单 const formObj = document.createElement('form'); formObj.action = downloadUrl; formObj.method = 'get'; formObj.style.display = 'none'; // 创建input,主要是起传参作用 const formItem = document.createElement('input'); formItem.value = fileName; // 传参的值 formItem.name = 'fileName'; // 传参的字段名 // 插入到网页中 formObj.appendChild(formItem); document.body.appendChild(formObj); formObj.submit(); // 发送请求 document.body.removeChild(formObj); // 发送完清除掉 }
2. a 标签的 download
html
<a href="example.jpg" download>点击下载</a>
<a href="example.jpg" download="test">点击下载</a> // 指定文件名
3. open或location.href
js
window.open('downloadFile.zip');
location.href = 'downloadFile.zip';
二、接口返回文件流
Blob对象
- 调用api,将文件流转为 Blob 二进制对象
- 注:IE10以下不支持。
- 思路: 发请求获取二进制数据,转化为Blob对象,利用URL.createObjectUrl生成url地址,赋值在a标签的href属性上,结合download进行下载。javascript
/** * 下载文件 * @param {String} path - 下载地址/下载请求地址。 * @param {String} name - 下载文件的名字/重命名(考虑到兼容性问题,最好加上后缀名) */ downloadFile (path, name){ const xhr = new XMLHttpRequest(); xhr.open('get', path); xhr.responseType = 'blob'; xhr.send(); xhr.onload = function () { if (this.status === 200 || this.status === 304) { // 如果是IE10及以上,不支持download属性,采用msSaveOrOpenBlob方法,但是IE10以下也不支持msSaveOrOpenBlob if ('msSaveOrOpenBlob' in navigator) { navigator.msSaveOrOpenBlob(this.response, name); return; } /* 如果发送请求时不设置xhr.responseType = 'blob', 默认ajax请求会返回DOMString类型的数据,即字符串。 此时需要使用两处注释的代码,对返回的文本转化为Blob对象,然后创建blob url, 此时需要注释掉原本的const url = URL.createObjectURL(target.response)。 */ /* const blob = new Blob([this.response], { type: xhr.getResponseHeader('Content-Type') }); const url = URL.createObjectURL(blob); */ const url = URL.createObjectURL(this.response); // 使用上面则注释此行 const a = document.createElement('a'); a.style.display = 'none'; a.href = url; a.download = name; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } }; }
javascript// 使用axios downloadFile (path, name){ axios.get({url: path, method: 'get' }).then(res => { const blob = new Blob([res.data], { type: res.headers['content-type'] }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.style.display = 'none'; a.href = url; a.download = name; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }) }
- 该方法不能缺少a标签的download属性的设置。
- 因为发请求时已设置返回数据类型为Blob类型(xhr.responseType = 'blob'),所以target.response就是一个Blob对象,打印出来会看到两个属性size和type。虽然type属性已指定了文件的类型,但是为了稳妥起见,还是在download属性值里指定后缀名,如Firefox不指定下载下来的文件就会不识别类型。
- 调用api,将文件流转为 Blob 二进制对象
利用Base64
- 用法跟上面用 Blob 大同小异,基本上思路一样
- 不同点: 上面是利用Blob对象生成 Blob URL, 这里则是生成 Data URL,即 base64 编码后的url形式。javascript
/** * 下载文件 * @param {String} path - 下载地址/下载请求地址。 * @param {String} name - 下载文件的名字(考虑到兼容性问题,最好加上后缀名) */ downloadFile (path, name){ const xhr = new XMLHttpRequest(); xhr.open('get', path); xhr.responseType = 'blob'; xhr.send(); xhr.onload = function () { if (this.status === 200 || this.status === 304) { const fileReader = new FileReader(); fileReader.readAsDataURL(this.response); fileReader.onload = function () { const a = document.createElement('a'); a.style.display = 'none'; a.href = this.result; a.download = name; document.body.appendChild(a); a.click(); document.body.removeChild(a); }; } }; }