You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

模态框二次打开后JSZip生成Zip但FileSaver的saveAs函数不触发问题

问题排查与解决方案

可能的原因

  1. 全局变量projectTitle失效:模态框关闭后,projectTitle可能被重置为undefined或空值,导致下载文件名参数异常,浏览器静默取消下载。
  2. FileSaver.js的上下文问题:模态框销毁时可能影响了FileSaver的内部状态,导致第二次调用saveAs无法正常触发。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 06:15:37