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

如何在JavaScript中重置XHR以避免Ajax重复提交?

解决Bootstrap模态框Ajax提交多次触发的问题

问题根源

你每次点击「创建商品分类」按钮时,都会执行document.getElementById('save_btn').addEventListener('click', ...),这会给同一个提交按钮重复绑定点击事件。第一次点击创建按钮绑定1次事件,第二次绑定2次,以此类推,导致每次提交时触发对应次数的Ajax请求,出现提交操作逐次递增的情况。这个问题和Ajax请求本身无关,核心是事件重复绑定。

解决方案

下面提供两种可行的修复方式:

方式1:使用事件委托(推荐)

将提交按钮的点击事件监听绑定到模态框的父容器上(比如modal-body),只需要绑定一次,无论模态框内容如何动态加载,事件都会生效,从根源避免重复绑定。

修改后的代码:

// 提前绑定事件委托,仅执行一次
document.getElementById('modal-body').addEventListener('click', function(e) {
    // 判断点击的元素是否是提交按钮
    if (e.target.id === 'save_btn') {
        e.preventDefault();
        console.log('save_btn')
        
        var xhr = new XMLHttpRequest();
        xhr.open('POST', `../includes/functions.php`, true)
        xhr.onload = function() {
            if (xhr.status == 200) {
                console.log(xhr.response)

                if (xhr.response == 'category name add successfully! ') {
                    document.getElementById('close_modal_btn').click();
                    showMessage(xhr.response, 'Add')
                    console.log(xhr.responseText)
                } else {
                    showMessage(xhr.response, 'Remove')
                    document.getElementById('logo_box').innerHTML = `<span class='text-danger'>${xhr.response}</span>`;
                }

                setTimeout(() => {
                    document.getElementById('table-body').innerHTML = '';
                    defaultLoad();
                    console.log("data Loaded")
                }, 5000)
            }
        }
        const formData = new FormData(document.getElementById('add_category_form'))
        xhr.send(formData);
    }
});

// 点击创建商品分类按钮加载模态框内容
document.getElementById('add_category').addEventListener('click', () => {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", 'add.php', true);
    console.log("add_category")
    xhr.onload = function() {
        if (this.status == 200) {
            document.getElementById('exampleModalLabel').innerHTML = 'Create Product Category';
            document.getElementById('modal-body').innerHTML = this.response;
            
            dynamicChangePicture();
            onChangeCategoryName('category_name');
        }
    }
    xhr.send();
})

方式2:每次加载内容时清除旧事件

将提交逻辑抽成独立函数,每次动态加载模态框内容后,通过克隆提交按钮的方式清除旧的事件监听,再绑定新的事件。

修改后的代码:

// 抽离提交逻辑为独立函数
function handleSaveCategory(e) {
    e.preventDefault();
    console.log('save_btn')
    
    var xhr = new XMLHttpRequest();
    xhr.open('POST', `../includes/functions.php`, true)
    xhr.onload = function() {
        if (xhr.status == 200) {
            console.log(xhr.response)

            if (xhr.response == 'category name add successfully! ') {
                document.getElementById('close_modal_btn').click();
                showMessage(xhr.response, 'Add')
                console.log(xhr.responseText)
            } else {
                showMessage(xhr.response, 'Remove')
                document.getElementById('logo_box').innerHTML = `<span class='text-danger'>${xhr.response}</span>`;
            }

            setTimeout(() => {
                document.getElementById('table-body').innerHTML = '';
                defaultLoad();
                console.log("data Loaded")
            }, 5000)
        }
    }
    const formData = new FormData(document.getElementById('add_category_form'))
    xhr.send(formData);
}

// 点击创建商品分类按钮加载模态框内容
document.getElementById('add_category').addEventListener('click', () => {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", 'add.php', true);
    console.log("add_category")
    xhr.onload = function() {
        if (this.status == 200) {
            document.getElementById('exampleModalLabel').innerHTML = 'Create Product Category';
            document.getElementById('modal-body').innerHTML = this.response;
            
            dynamicChangePicture();
            onChangeCategoryName('category_name');

            // 克隆按钮清除旧事件,再绑定新事件
            const saveBtn = document.getElementById('save_btn');
            const newSaveBtn = saveBtn.cloneNode(true);
            saveBtn.parentNode.replaceChild(newSaveBtn, saveBtn);
            newSaveBtn.addEventListener('click', handleSaveCategory);
        }
    }
    xhr.send();
})

说明

两种方式都能解决重复提交的问题,事件委托更高效,不需要每次处理元素的克隆或事件移除,推荐使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:05:31