Javascript 如何在不丢失任何数据的情况下防止双重表单提交?

Javascript 如何在不丢失任何数据的情况下防止双重表单提交?,javascript,jquery,html,forms,usability,Javascript,Jquery,Html,Forms,Usability,我有一个带有两个按钮的HTML表单 <form action="..."> ... <input type="submit" name="button1" value="Localized button 1"> <input type="submit" name="button2" value="Otro botón"> <form> (加上一些CSS转换和动画,使。提交看起来不错) 上面的代码试图防止双重表单提交,因为有

我有一个带有两个按钮的HTML表单

<form action="...">
    ...
    <input type="submit" name="button1" value="Localized button 1">
    <input type="submit" name="button2" value="Otro botón">
<form>
(加上一些CSS转换和动画,使
。提交
看起来不错)

上面的代码试图防止双重表单提交,因为有些人似乎误解了web,并一直双击普通表单提交按钮。还有一些人因为握手或鼠标按钮坏了而对触摸屏有问题,所以这也是可用性的问题

问题在于,Google Chrome在收集表单提交时发送的数据之前,会在(“提交”)上运行事件处理程序
。因此,HTML5规则(如果其控件被禁用,则不发送输入值)妨碍了服务器,并阻止服务器可以看到的请求中包含任何提交按钮。(服务器正在查找参数
button1
button2
,但忽略实际值,因为它是由于历史HTML表单规则而本地化的字符串。)

如何在遵守HTML5规则的浏览器上禁用提交按钮,并且仍然可以获取有关实际按下按钮的信息?我非常希望有一个具有语义正确的HTML5源代码的解决方案。是否有方法在收集表单数据并将其传输到服务器后运行代码

有些相关的非重复项(请不要将其标记为其中任何一项的重复项):

附加要求:

  • 允许在延迟(上例中为10秒)后重新提交表单,以允许用户解决网络连接中断等问题,或进行有意的双重提交
  • 没有快速的解决方案(例如,在实际的
    on(“提交”)
    事件后,运行上述代码并短暂超时,希望浏览器已收集数据,但用户速度不够快,无法双击按钮)
  • 表单仍应在禁用JavaScript的情况下工作-在这种情况下,没有双重表单提交预防是可以的
  • 没有像向DOM中添加包含缺少参数的隐藏表单输入这样的黑客行为

如何使用
onClick()
劫持单击并在禁用按钮之前提交表单

[未经测试]

$('input[type=submit]').click(function(e) {
    var $submitButton = $(e.target);

    // prevent automatic form submission
    e.preventDefault();

    // prevent double click without disabling
    if (! $submitButton.hasClass('submitting')) {
        $submitButton.addClass('submitting');

        // submit your form contents
        $('#your-form-id').submit();

        // disable all submit buttons
        $(this).find("input[type=submit], button").each(function()
        {
            var $button = $(this);
            $button.attr("disabled", "disabled");
            $button.addClass("submitting");
            setTimeout(function()
            {
                $button.removeAttr("disabled");
                $button.removeClass("submitting");
            }, 10000); // remove disabled status after timeout (ms)
        });
    }
});

以下是一个对于生产使用来说足够健壮的实现:

    // prevent double submit and display a nice animation while submitting
    $(document).on("submit", "form", function(event)
    {
        $(this).find("input[type=submit], button").each(function()
        {
            var $button = $(this);

            if ($button.attr("disabled"))
                return; // this button is already disabled, do not touch it

            setTimeout(function()
            {
                $button.attr("disabled", "disabled");
                $button.addClass("submitting");
                setTimeout(function()
                {
                    $button.removeAttr("disabled");
                    $button.removeClass("submitting");
                }, 10000); // remove disabled status after timeout (ms)
            }, 0); // let the event loop run before disabling the buttons to allow form submission to collect form data (and emit "formdata" event) before disabling any buttons and hope that user is not fast enough to double submit before this happens
        });
    });

设置超时(…,0)
是一种允许Chrome运行其事件循环一次,让Chrome在禁用按钮之前收集表单数据的黑客行为,该按钮会从提交的数据中删除有关按钮的信息。据我所知,这对用户输入不太方便,因为我们可以在此处使用延迟
0
,用户无法使用零延迟。

您是否考虑过将它们改为
,然后在正在执行的代码中添加代码以提交表单?显示一个模式弹出窗口,说“提交时加载,页面加载时隐藏”。@JoSSte在这种情况下,我要么无法将按钮设置为禁用,要么必须添加一个与我所述完全相同的隐藏表单输入不想这样做。@bestinamir显示覆盖视觉表单的内容可能不会阻止通过键盘重新提交。仔细想想,您甚至不需要禁用按钮。只需添加“提交”单击其中一个时,将两个都初始化。如果用户在任何文本字段中按enter键提交表单,则在
单击中运行代码可能会失败。@MikkoRantalainen如果您想消除这种情况,您可以:还可以使用上面的“jquery事件名称空间”并将
设置为on(“提交。防止双重提交”,…
相反,因此可以使用
.off(“.protect double submit”);
    // prevent double submit and display a nice animation while submitting
    $(document).on("submit", "form", function(event)
    {
        $(this).find("input[type=submit], button").each(function()
        {
            var $button = $(this);

            if ($button.attr("disabled"))
                return; // this button is already disabled, do not touch it

            setTimeout(function()
            {
                $button.attr("disabled", "disabled");
                $button.addClass("submitting");
                setTimeout(function()
                {
                    $button.removeAttr("disabled");
                    $button.removeClass("submitting");
                }, 10000); // remove disabled status after timeout (ms)
            }, 0); // let the event loop run before disabling the buttons to allow form submission to collect form data (and emit "formdata" event) before disabling any buttons and hope that user is not fast enough to double submit before this happens
        });
    });