项目背景 : react + ant
需导出三种格式 excel csv txt
注 : 我没有用插件 , 用的是浏览器的下载功能
其中 excel 后台返回了blob文件流格式 , 其他是正常格式
故 需单独处理
const Blobs = new Blob([res.data]);
if (format.includes('xlsx')) {
fileName = res.fileName.split('filename=')[1] || Date.now() + '.xlsx';
} else if (format.includes('csv')) {
fileName = Date.now() + '.csv';
} else if (format.includes('txt')) {
fileName = Date.now() + '.txt';
}
const url = window.URL.createObjectURL(Blobs);
const link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(link.href);
1. 需在响应拦截器中做单独处理文件流下载 (否则会出现csv txt等格式可以下载 , 而文件流的excel格式无法下载也不报错)
我们可以在响应拦截器中log一下 , 其实我们只需要response.data和响应标头中的filename


故导出整体代码如下
// 响应拦截器 (这样即可)
axios.interceptors.response.use(
(response) => {
console.log('响应拦截器的response', response);
if (response.request.responseType === 'blob') {
return Promise.resolve({
data: response.data,
fileName: response.headers['content-disposition'] || '',
});
}
return Promise.resolve(response);
},
(error) => {
console.log(error);
return Promise.reject(error);
},
);
---------------------------------------------------
在发请求的js中添加标识
// 导出用户
const getDerive = async (obj) => {
try {
const res = await axios.post('/api/v1/help/export', obj, {
responseType: 'blob',
});
const code = get(res, 'data.code', 0);
const data = get(res, 'data.data', []);
const msg = get(res, 'data.message', '数据获取失败!');
if (code === 200) {
return data;
} else {
return res;
}
} catch (error) {
return false;
}
};
----------------------------------------------------
在jsx中 进行导出操作
const Blobs = new Blob([res.data]);
if (format.includes('xlsx')) {
fileName = res.fileName.split('filename=')[1] || Date.now() + '.xlsx';
} else if (format.includes('csv')) {
fileName = Date.now() + '.csv';
} else if (format.includes('txt')) {
fileName = Date.now() + '.txt';
}
const url = window.URL.createObjectURL(Blobs);
const link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(link.href);
拓 : react的一个小坑点 , 用ant-menu实现导出时选中不同格式
需实现效果如下 : 可以连续选中excel格式或者其他格式

问题就是 : 选择完excel格式后再选excel不能选中了, 只能选其他格式 , 起初我以为是组件没销毁

后来发现不是菜单组件没销毁 , 而是setState操作通常是异步的 , 当我设置setFormat('csv')时它没监听到 , 虽然ref也是异步操作 , 但ref.current 属性可以被修改而不会引发组件的重新渲染 , 可以直接拿到想要的值
解决如下
// 旧代码如下
const [format, setFormat] = useState('');
const formatCounter = useRef(0); // 设置一个字符串为了点击下拉菜单
<Dropdown
menu={{
items: [
{
label: (
<a
onClick={() => {
setFormat(`xlsx`); // 旧代码
setFormat(`xlsx${formatCounter.current}`); // 这样就可以了
formatCounter.current++;
}}
>
{t('derive3')}
</a>
),
key: '1',
},
{
label: (
<a
onClick={() => {
setFormat(`csv`); // 旧代码
setFormat(`csv${formatCounter.current}`); // 这样就可以了
formatCounter.current++;
}}
>
{t('derive4')}
</a>
),
key: '2',
},
{
label: (
<a
onClick={() => {
setFormat(`txt`); // 旧代码
setFormat(`txt${formatCounter.current}`); // 这样就可以了
formatCounter.current++;
}}
>
{t('derive5')}
</a>
),
key: '3',
},
],
}}
>
// 点击弹出导出弹窗
useEffect(() => {
if (format) {
setDeriveModal(true);
}
}, [format]);