项目中用到下载导出功能实现:
第一、二、三种方法是通用方法,vue\react\js都可以使用,当然也有react专用的(实际上是react的方法实现)。
一般都是从接口获取到文件地址,然后调用下面的方法即可,如果下载多个文件就只能循环调用了。
第一种方法iframe实现:
只需要传一个文件下载地址的url即可
downloadFile = (url) => {//下载方法
console.log(url)
const iframe = document.createElement("iframe");
iframe.style.display = "none"; // 防止影响页面
iframe.style.height = 0; // 防止影响页面
iframe.src = url;
document.body.appendChild(iframe); // 这一行必须,iframe挂在到dom树上才会发请求
// 5分钟之后删除(onload方法对于下载链接不起作用,就先抠脚一下吧)
setTimeout(() => {
iframe.remove();
}, 5 * 60 * 1000);
}
第二种方法a标签:
downloadFile = ((fileurl, filename) => { //fileurl文件地址(一般是接口返回) filename文件下载后的名字
console.log("3333")
var a = document.createElement('a');
a.download = filename; //下载后文件名
a.style.display = 'none';
var blob = new Blob([fileurl]); // 字符内容转变成blob地址 二进制地址
a.href = URL.createObjectURL(blob);
document.body.appendChild(a);
a.click(); // 触发点击
document.body.removeChild(a); // 然后移除
});
文件名必须要和你下载得文件后缀名一致。要不然下载下来打不开。
2023-05-31补充:
上面的方法有些问题,传了文件名会导致文件损毁。所以把filename去掉了
const downloadFile = (fileurl,filename) => { //fileurl文件地址(一般是接口返回)
const a = document.createElement("a");
a.style.display = "none";
a.href = fileurl;
a.download = filename || ""; //需要把这行加上,告诉浏览器是下载行为 ,可以传空
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
第三中方法form表单:
exportCallBack = (fileUrl) => {
var bodyElement = document.body; //获取body
var divElement = document.createElement("div"); //创建div
var downloadUrl = fileUrl; //文件地址
divElement.innerHTML = `<form action=${downloadUrl} method="post" id="formBox"></form>` //form标签
bodyElement.appendChild(divElement); //追加到body
document.getElementById("formBox").submit(); //自动提交表单
bodyElement.removeChild(divElement); //移除form
}
react里专用的方法(显得很鸡肋):
这个方法很麻烦,需要先引入
import ReactDOM from "react-dom";
然后再项目中跟组件加上这一行或者在使用的组件,render里加上这一行
<div id="exportBoxBank"></div>
exportCallBack = (fileUrl) => {
var divElement = document.getElementById('exportBoxBank'); //获取div 也可以用ref获取
var downloadUrl = fileUrl; //文件地址
ReactDOM.render(<form action={downloadUrl} method="post" id="formBox"></form>, divElement);
document.getElementById("formBox").submit(); //自动提交表单
ReactDOM.unmountComponentAtNode(divElement) //ReactDOM.unmountComponentAtNode()方法,参数为一个结点,调用方法会卸载该容器中的渲染
}
大致的伪代码:
import React, { Component } from 'react';
import ReactDOM from "react-dom";
class Index9 extends Component {
exportCallBack = (fileUrl) => {
var divElement = document.getElementById('exportBoxBank'); //获取div 也可以用ref获取
var downloadUrl = fileUrl; //文件地址
ReactDOM.render(<form action={downloadUrl} method="post" id="formBox"></form>, divElement);
document.getElementById("formBox").submit(); //自动提交表单
ReactDOM.unmountComponentAtNode(divElement) //ReactDOM.unmountComponentAtNode()方法,参数为一个结点,调用方法会卸载该容器中的渲染
}
exportFile=()=>{//点击导出
//一般都是先请求接口获取到文件地址然后调用事件(涉及跨域的使设置用代理解决)
this.exportCallBack(url);
}
render() {
return (
<div>
<button onClick={exportFile}>导出</button>
{/* 放到末尾 */}
<div id="exportBoxBank"></div>
</div>
);
}
}
export default Index9;
解决下载文件乱码和有空格问题(2023-10-17补充):
当下载的url路径中有 # 、空格、+等特殊字符时可以使用 js里的 encodeURIComponent 对有些参数进行编码。
比如:fileUrl="http://api/download?filename=aa#b"
如果不加 encodeURIComponent 的话是无法下载的,需要处理一下:
fileUrl=`http://api/download?filename=${encodeURIComponent(aa#b)}`
其实我还遇到了个问题就是如果我的 文件名有空格。下载的时候浏览器自动转换成了+号。、这个应该跟浏览器版本有关,新版本应该就没这个问题了。
不过空格被转换成+号,应该跟 浏览器版本有关