如何监听window.open()发起的PDF下载请求完成状态?
问题解答
首先明确:window.open()无法追踪下载请求的完成状态。因为用window.open触发的下载是由浏览器独立处理的,JS无法监听这个请求的成功、失败或完成事件,没法和你的加载动画逻辑联动。
想要实现「点击按钮显示加载动画,下载完成后隐藏」的效果,可以用fetch(或XMLHttpRequest)先请求文件资源,拿到Blob后再触发下载,这样就能全程监控请求状态,具体实现步骤如下:
实现思路
- 点击按钮时,立即切换按钮状态(禁用+显示加载文案/动画)
- 用fetch请求PDF接口,监听请求的成功/失败
- 拿到响应后转为Blob对象,创建临时下载链接触发浏览器下载
- 无论请求成功还是失败,最后都恢复按钮状态,隐藏加载动画
代码示例
<button id="pdfDownloadBtn">下载PDF</button>
const downloadBtn = document.getElementById('pdfDownloadBtn'); downloadBtn.addEventListener('click', async () => { // 开启加载状态 downloadBtn.disabled = true; downloadBtn.innerHTML = '<span>下载中...</span>'; // 这里可以替换成你自己的加载动画HTML try { // 发起请求 const response = await fetch('/download-pdf'); if (!response.ok) { throw new Error(`请求失败:${response.status}`); } // 将响应转为Blob const pdfBlob = await response.blob(); // 解析后端返回的文件名(如果后端设置了Content-Disposition) let filename = '文档.pdf'; const contentDisposition = response.headers.get('Content-Disposition'); if (contentDisposition) { const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); if (filenameMatch?.[1]) { filename = decodeURIComponent(filenameMatch[1].replace(/['"]/g, '')); } } // 创建临时下载链接并触发下载 const downloadUrl = window.URL.createObjectURL(pdfBlob); const aTag = document.createElement('a'); aTag.href = downloadUrl; aTag.download = filename; document.body.appendChild(aTag); aTag.click(); // 清理临时资源 window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(aTag); } catch (err) { console.error('下载出错:', err); alert('下载失败,请稍后重试'); } finally { // 恢复按钮状态,关闭加载动画 downloadBtn.disabled = false; downloadBtn.innerHTML = '下载PDF'; } });
注意事项
- 如果后端接口是跨域的,需要确保后端配置了正确的CORS规则,允许前端发起请求
- 后端最好设置
Content-Type: application/pdf和Content-Disposition: attachment; filename="你的文件名.pdf",这样前端可以正确解析文件名,浏览器也能识别文件类型 - 若需要兼容旧浏览器,可以把
fetch换成XMLHttpRequest,逻辑是一致的,只是写法不同
内容的提问来源于stack exchange,提问作者pileup
相关产品推荐
相关产品推荐

