一、文件下载的几种方式
1、window.open()
2、创建a标签
function download(url) {
if(!url) return
const el = document.createElement('a')
el.href = url
el.target = '_blank'
document.body.appendChild(el)
el.click()
document.body.removeChild(el)
}
3、接收的是文件流的情况
function downloadBlob(blobRes, fileName) {
if(!blobRes) return;
const blob = new Blob([blobRes]);
const el = document.createElement('a')
const url = (window.URL ? window.URL : window.webkitURL).createObjectURL(blob)
el.href = url
el.download = fileName
document.body.appendChild(el)
el.click()
document.body.removeChild(el)
}
二、浏览器下载窗口被拦截问题
在浏览器的安全机制里,非用户触发的弹出窗口window.open()会被阻止,会被认为是用户不希望打开的新页面。
在用户触发异步函数内触发下载,超过一定时间也有可能会被拦截。
1、先新增标签页,异步返回之后替换对应的地址
const onDownload = async () => {
// 这种方式会有一个空白页面,对用户不是很友好
const newTab = window.open()
// 可先打开一个加载页面 const newTab = window.open(loadingUrl)
const url = await api()
if(url) {
newTab.location = url;
}else {
newTab.close()
}
}
2、被拦截后,提示用户手动下载
(1)、react hooks
import React from "react";
import { remindCloseWarning } from "../utils/remind";
// 打开下载窗口被拦截后提示手动下载
export const useWindowOpen = () => {
function windowOpenWithCheck(url) {
if (!url) return;
const tab = window.open(url);
// 被拦截
if (!tab) {
const closeWarning = remindCloseWarning("下载弹窗未能正常打开,请手动下载!", {
operateView: (
<>
<a
href={url}
target='_blank'
onClick={() => {
closeWarning && closeWarning();
}}
style={{ marginLeft: "8px", textDecoration: "underline" }}
>
点击下载
</a>
</>
),
});
}
}
return [windowOpenWithCheck];
};
(2)、使用
const [windowOpenWithCheck] = useWindowOpen();
const onDownload = async () => {
const url = await api();
if(url) {
windowOpenWithCheck(url)
}
}
(3)、效果