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

Fetch重复执行致项目多次创建的问题排查与解决求助

问题根源

你遇到的重复创建问题,核心原因是每次调用verifierboutonValider时,尝试移除的是匿名函数,但匿名函数无法被精准匹配移除,导致之前添加的submit监听一直残留。同时每次符合validPhoto && validTitre && validCategorie条件时,又会新增一个submit监听,最终监听数量随verifierboutonValider调用次数递增,提交表单时就会触发多次enregistrerProjet。

解决方案

方案一:提取命名回调函数(精准管理监听)

把submit监听的回调改成命名函数,让removeEventListener可以精准定位并移除旧监听,避免叠加:

// 提取命名回调函数,统一处理表单提交逻辑
async function handleFormSubmit(e) {
    e.preventDefault();
    // 二次校验防止状态变化导致误提交
    if (validPhoto && validTitre && validCategorie) {
        await enregistrerProjet(imageInput, titleInput, categoryInput);
    }
}

// ******************************* FONCTION ENREGISTREMENT DU NOUVEAU PROJET *************************************
let errorMessage = document.getElementById("errorMessage");
async function enregistrerProjet(imageInput, titleInput, categoryInput) {
    const formData = new FormData();
    formData.append("image", imageInput);
    formData.append("title", titleInput);
    formData.append("category", categoryInput);

    try {
        const response = await fetch("http://localhost:5678/api/works", {
            method: "POST",
            headers: {
                "accept": "application/json",
                "Authorization": "Bearer " + tokenLogin,
            },
            body: formData,
        })
        const responseProjet = await response.json();
        
        if (!response.ok) {
            throw new Error(`Une erreur s'est produite lors de l'ajout d'un élément (${response.status}). Veuillez réessayer plus tard.`)
        }
        projets.push(responseProjet);

        // 优化DOM操作:直接重新生成画廊,无需先添加再清空
        document.querySelector(".gallery").innerHTML = "";
        genererProjets(projets);

        document.getElementById("modifyProject").className = "modal-masque";
        document.getElementById("galeriePhoto").className = "modal-wrapper";
        masquerModaleAjoutphoto();

    } catch (error) {
        errorMessage.textContent = "Erreur d'envoi du projet.";
        // 优化错误监听:用命名函数+once选项,避免监听叠加
        const clearError = (event) => {
            event.preventDefault();
            errorMessage.textContent = "";
            // 触发后自动移除监听
            document.removeEventListener("keydown", clearError);
            document.removeEventListener("click", clearError);
        };
        document.addEventListener("keydown", clearError, { once: true });
        document.addEventListener("click", clearError, { once: true });
        alert(error);
    };
};

// ********************** FONCTION ACTIVATION/DESACTIVATION DU BOUTON DE VALIDATION ****************************
function verifierboutonValider() {
    const boutonValidationprojet = document.getElementById("boutonValidprojet");
    const formulaire = document.getElementById("formulaire");

    // 移除旧的命名回调监听
    formulaire.removeEventListener("submit", handleFormSubmit);

    if (validPhoto && validTitre && validCategorie) {
        boutonValidationprojet.className = "btn-on_2";
        // 添加命名回调监听
        formulaire.addEventListener("submit", handleFormSubmit);
    } else {
        boutonValidationprojet.className = "btn-off_2";
    };
};

方案二:初始化单次监听(更简洁推荐)

直接在页面初始化时给表单添加一次submit监听,verifierboutonValider只负责切换按钮样式,完全不用处理监听的添加/移除:

// 页面初始化时添加一次表单提交监听
document.getElementById("formulaire").addEventListener("submit", async function(e) {
    e.preventDefault();
    // 仅当校验通过时执行提交逻辑
    if (validPhoto && validTitre && validCategorie) {
        await enregistrerProjet(imageInput, titleInput, categoryInput);
    }
});

// ******************************* FONCTION ENREGISTREMENT DU NOUVEAU PROJET *************************************
let errorMessage = document.getElementById("errorMessage");
async function enregistrerProjet(imageInput, titleInput, categoryInput) {
    // 原函数内容保持不变,仅优化错误监听和DOM操作(同方案一)
    const formData = new FormData();
    formData.append("image", imageInput);
    formData.append("title", titleInput);
    formData.append("category", categoryInput);

    try {
        const response = await fetch("http://localhost:5678/api/works", {
            method: "POST",
            headers: {
                "accept": "application/json",
                "Authorization": "Bearer " + tokenLogin,
            },
            body: formData,
        })
        const responseProjet = await response.json();
        
        if (!response.ok) {
            throw new Error(`Une erreur s'est produite lors de l'ajout d'un élément (${response.status}). Veuillez réessayer plus tard.`)
        }
        projets.push(responseProjet);

        document.querySelector(".gallery").innerHTML = "";
        genererProjets(projets);

        document.getElementById("modifyProject").className = "modal-masque";
        document.getElementById("galeriePhoto").className = "modal-wrapper";
        masquerModaleAjoutphoto();

    } catch (error) {
        errorMessage.textContent = "Erreur d'envoi du projet.";
        const clearError = (event) => {
            event.preventDefault();
            errorMessage.textContent = "";
            document.removeEventListener("keydown", clearError);
            document.removeEventListener("click", clearError);
        };
        document.addEventListener("keydown", clearError, { once: true });
        document.addEventListener("click", clearError, { once: true });
        alert(error);
    };
};

// ********************** FONCTION ACTIVATION/DESACTIVATION DU BOUTON DE VALIDATION ****************************
function verifierboutonValider() {
    const boutonValidationprojet = document.getElementById("boutonValidprojet");
    // 只负责按钮样式切换,不再处理监听逻辑
    if (validPhoto && validTitre && validCategorie) {
        boutonValidationprojet.className = "btn-on_2";
    } else {
        boutonValidationprojet.className = "btn-off_2";
    };
};

额外优化说明

  • 错误处理中的监听:原代码每次报错都会新增keydown/click监听,改成命名函数+{ once: true }后,监听触发一次会自动移除,避免残留。
  • DOM操作冗余:原函数中先添加新元素再清空画廊,直接调用genererProjets(projets)即可完成刷新,无需重复操作。

内容的提问来源于stack exchange,提问作者Fred2460

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:23:13