防止在 jQuery 中重复提交表单

IT技术 javascript jquery double-submit-prevention forms http-post
2021-01-23 04:05:16

我有一个需要服务器处理一段时间的表单。我需要确保用户等待并且不会尝试通过再次单击按钮来重新提交表单。我尝试使用以下 jQuery 代码:

<script type="text/javascript">
$(document).ready(function() {
    $("form#my_form").submit(function() {
        $('input').attr('disabled', 'disabled');
        $('a').attr('disabled', 'disabled');
        return true;
    });
});
</script>

当我在 Firefox 中尝试此操作时,所有内容都被禁用,但表单未与它应该包含的任何 POST 数据一起提交。我无法使用 jQuery 提交表单,因为我需要将按钮与表单一起提交,因为有多个提交按钮,并且我确定 POST 中包含哪个值。我需要像往常一样提交表单,并且我需要在发生这种情况后立即禁用所有内容。

谢谢!

6个回答

2018 年更新:我刚刚从这个旧答案中得到了一些分数,只是想补充一点,最好的解决方案是使操作具有幂等性,以便重复提交无害。

例如,如果表单创建了一个订单,则在表单中放置一个唯一的 ID。服务器第一次看到具有该 id 的订单创建请求时,它应该创建它并响应“成功”。随后的提交也应该响应“成功”(以防客户没有得到第一个响应)但不应该改变任何东西。

应通过数据库中的唯一性检查来检测重复项,以防止出现竞争条件。


我认为你的问题是这一行:

$('input').attr('disabled','disabled');

您正在禁用所有输入,包括,我猜,表单应该提交其数据的那些。

要仅禁用提交按钮,您可以这样做:

$('button[type=submit], input[type=submit]').prop('disabled',true);

但是,我认为即使这些按钮被禁用,IE 也不会提交表单。我建议采用不同的方法。

一个jQuery插件来解决它

我们刚刚用下面的代码解决了这个问题。这里的技巧是使用 jQuerydata()来标记表单是否已经提交。这样,我们就不必弄乱提交按钮,这让 IE 感到害怕。

// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function() {
  $(this).on('submit',function(e){
    var $form = $(this);

    if ($form.data('submitted') === true) {
      // Previously submitted - don't submit again
      e.preventDefault();
    } else {
      // Mark it so that the next submit can be ignored
      $form.data('submitted', true);
    }
  });

  // Keep chainability
  return this;
};

像这样使用它:

$('form').preventDoubleSubmission();

如果有应该允许每次页面加载多次提交的AJAX 表单,您可以给它们一个指示这一点的类,然后将它们从您的选择器中排除,如下所示:

$('form:not(.js-allow-double-submission)').preventDoubleSubmission();
只是一个指针 - 将$(this)a缓存不是更好var that = $(this)吗?
2021-03-16 04:05:16
@Stuart.Sklinar - 好主意。$form虽然使用了 - 'form' 因为它更具描述性,而领先$是因为根据我的约定,这意味着它是一个 jQuery 对象。
2021-03-18 04:05:16
@BrianMacKay 如果表单无效并按下提交按钮,则此 jquery 插件将提交的属性标记为 true 但不显眼的验证会阻止由于验证错误而导致的提交。更正错误后无法提交表单,因为提交的属性为真!
2021-03-21 04:05:16
当使用 jquery 验证不显眼的验证时,可以更好地检查表单是否有效。if ($(this).valid)) {$form.data('submitted', true);}
2021-03-27 04:05:16
@cck 太棒了,我用过。我删除了一个额外的结束括号: if ($(this).valid) {$form.data('submitted', true);
2021-03-29 04:05:16

计时方法是错误的 - 你怎么知道客户端浏览器上的操作需要多长时间?

怎么做

$('form').submit(function(){
  $(this).find(':submit').attr('disabled','disabled');
});

提交表单时,它将禁用其中的所有提交按钮。

请记住,在 Firefox 中,当您禁用按钮时,该状态将在您返回历史记录时被记住。例如,为了防止您必须在页面加载时启用按钮。

根据最新的 jQuery 文档,您应该使用 .prop 而不是 .attr。参考:api.jquery.com/prop/#entry-longdesc-1 “应该使用 .prop() 方法来设置禁用和检查,而不是 .attr() 方法。“
2021-03-16 04:05:16
这是最干净的方式。我试图用点击事件处理程序禁用提交按钮,但我的方法导致 chrome 出现问题。这个解决方案效果很好。
2021-03-19 04:05:16
使用这种方法时要非常小心,如果您在提交按钮上有一个值并且您需要它,表单将不会提交它。
2021-03-30 04:05:16
+1 因为 Firefox 提示,但是除了在页面加载时启用按钮之外还有其他选项吗?
2021-04-01 04:05:16

我认为 Nathan Long 的答案是要走的路。对我来说,我使用的是客户端验证,所以我只添加了表单有效的条件。

编辑:如果没有添加,如果客户端验证遇到错误,用户将永远无法提交表单。

        // jQuery plugin to prevent double submission of forms
        jQuery.fn.preventDoubleSubmission = function () {
            $(this).on('submit', function (e) {
                var $form = $(this);

                if ($form.data('submitted') === true) {
                    // Previously submitted - don't submit again
                    alert('Form already submitted. Please wait.');
                    e.preventDefault();
                } else {
                    // Mark it so that the next submit can be ignored
                    // ADDED requirement that form be valid
                    if($form.valid()) {
                        $form.data('submitted', true);
                    }
                }
            });

            // Keep chainability
            return this;
        };

event.timeStamp在 Firefox 中不起作用。返回 false 是非标准的,您应该调用event.preventDefault(). 当我们这样做时,请始终使用带有控制结构的大括号

总结所有以前的答案,这里有一个插件可以完成工作并跨浏览器工作。

jQuery.fn.preventDoubleSubmission = function() {

    var last_clicked, time_since_clicked;

    jQuery(this).bind('submit', function(event) {

        if(last_clicked) {
            time_since_clicked = jQuery.now() - last_clicked;
        }

        last_clicked = jQuery.now();

        if(time_since_clicked < 2000) {
            // Blocking form submit because it was too soon after the last submit.
            event.preventDefault();
        }

        return true;
    });
};

为了解决 Kern3l,计时方法对我有用,因为我们试图停止双击提交按钮。如果您对提交的响应时间很长,我建议用微调器替换提交按钮或表单。

完全阻止表单的后续提交,就像上面的大多数例子一样,有一个不好的副作用:如果出现网络故障并且他们想尝试重新提交,他们将无法这样做并且会丢失他们所做的更改制成。这肯定会让用户生气。

你说得对。您可以反过来 - 立即禁用,然后在长时间超时后再次启用。防止双击,允许重新提交,但仍然允许滞后用户进行无效的重新提交。
2021-03-15 04:05:16

请查看jquery-safeform插件。

用法示例:

$('.safeform').safeform({
    timeout: 5000,  // disable next submission for 5 sec
    submit: function() {
        // You can put validation and ajax stuff here...

        // When done no need to wait for timeout, re-enable the form ASAP
        $(this).safeform('complete');
        return false;
    }
});