模态框二次打开后JSZip生成Zip但FileSaver的saveAs函数不触发问题
问题排查与解决方案
可能的原因
- 全局变量
projectTitle失效:模态框关闭后,projectTitle可能被重置为undefined或空值,导致下载文件名参数异常,浏览器静默取消下载。 - FileSaver.js的上下文问题:模态框销毁时可能影响了FileSaver的内部状态,导致第二次调用
saveAs无法正常触发。 - JSZip实例残留:重复创建JSZip实例但未及时清理,可能导致后续生成的Blob无法正确触发下载流程。
具体修复方案
1. 替换saveAs为原生下载逻辑
抛弃对FileSaver.js的依赖,使用浏览器原生API实现下载,避免第三方库的上下文问题:
function createZipFile(jsonData) { const zip = new JSZip(); let files = {}; jsonData.map((obj) => Object.entries(obj).forEach(([key, value]) => { files[key] = Object.assign(...value); }) ); Object.entries(files).forEach(([key, value]) => { zip.file(`${key}.json`, JSON.stringify(value)); }); zip.generateAsync({ type: "blob" }).then(function (content) { // 原生下载逻辑 const downloadUrl = URL.createObjectURL(content); const link = document.createElement('a'); link.href = downloadUrl; // 给文件名加默认值,避免空值导致下载失败 link.download = `${projectTitle || 'my-project'}.zip`; // 临时添加到DOM再触发点击 document.body.appendChild(link); link.click(); // 清理DOM和URL对象,避免内存泄漏 document.body.removeChild(link); URL.revokeObjectURL(downloadUrl); }); }
2. 确保projectTitle的有效性
避免依赖全局变量,改为将projectTitle作为参数传入函数,确保每次调用都有有效值:
// 修改函数定义,接收projectTitle参数 function createZipFile(jsonData, projectTitle) { const zip = new JSZip(); let files = {}; jsonData.map((obj) => Object.entries(obj).forEach(([key, value]) => { files[key] = Object.assign(...value); }) ); Object.entries(files).forEach(([key, value]) => { zip.file(`${key}.json`, JSON.stringify(value)); }); zip.generateAsync({ type: "blob" }).then(function (content) { const downloadUrl = URL.createObjectURL(content); const link = document.createElement('a'); link.href = downloadUrl; // 使用传入的参数,同时保留默认值 link.download = `${projectTitle || 'my-project'}.zip`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(downloadUrl); }); } // 调用时传入projectTitle createZipFile(yourJsonData, currentProjectTitle);
3. 检查模态框的事件绑定
如果模态框是动态渲染(关闭后销毁DOM,打开时重新生成),确保按钮的点击事件每次打开模态框时都重新绑定,或者使用事件委托绑定到模态框的父容器:
// 事件委托示例,绑定到父容器(比如id为modal-container的元素) document.getElementById('modal-container').addEventListener('click', function(e) { if (e.target.matches('.download-zip-btn')) { // 触发下载逻辑 createZipFile(yourJsonData, projectTitle); } });
4. 手动清理JSZip实例(可选)
在函数执行完成后手动清理JSZip实例,避免内存泄漏:
function createZipFile(jsonData, projectTitle) { let zip = new JSZip(); let files = {}; jsonData.map((obj) => Object.entries(obj).forEach(([key, value]) => { files[key] = Object.assign(...value); }) ); Object.entries(files).forEach(([key, value]) => { zip.file(`${key}.json`, JSON.stringify(value)); }); zip.generateAsync({ type: "blob" }).then(function (content) { const downloadUrl = URL.createObjectURL(content); const link = document.createElement('a'); link.href = downloadUrl; link.download = `${projectTitle || 'my-project'}.zip`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(downloadUrl); // 清理实例 zip = null; }); }
内容的提问来源于stack exchange,提问作者Teq Teq
相关产品推荐
相关产品推荐

