jQuery事件处理程序如何排队和执行?

时间:2019-04-04 06:14:31

标签: javascript jquery html form-submit

我有一个输入表单,带有一个提交按钮。我不希望用户能够双击提交按钮并再次提交表单...

因此,我已在表单中添加了以下jQuery:

var prevSubmitTime = new Date('2000-01-01');

function preventFromBeingDoubleSubmitted() {
    $('form').each(function () {
        $(this).submit(function (e) {
            if ($("form").valid()) {
                var curSubmitTime = new Date($.now());

                // prevent the second submit if it is within 2 seconds of the first submit
                if (curSubmitTime - prevSubmitTime < 2000) {
                    e.preventDefault();
                }
                prevSubmitTime = new Date($.now());
            }
        });
    });
}

$(document).ready(function () {
    preventFromBeingDoubleSubmitted();
});

上面的代码存储了提交时间,并阻止了第二次提交,如果为时过早(少于2秒),我不希望永久禁用提交按钮,以防服务器端出现错误。

此代码可以满足我的要求,但是在调试代码时,即使双击提交按钮,我也永远无法触及e.preventDefault();的断点。

似乎第二个提交事件正在等待第一个提交事件完成,然后再触发。

但是,如果我删除了preventFromBeingDoubleSubmitted()函数,则可以通过双击“提交”按钮来两次提交表单。

任何人都可以解释为什么有时有时一次又一次触发提交事件...有时不是这种情况吗?将事件处理程序放入.each()内是否会影响其执行行为?

5 个答案:

答案 0 :(得分:4)

在您的代码段中,我添加了一些可能有用的日志。当您提出多个问题时,我将一一回答。

var prevSubmitTime = new Date('2000-01-01');

function preventFromBeingDoubleSubmitted() {
    $('form').each(function () {
        $(this).submit(function (e) {
            console.log('I am going to submit form');
            if ($("form").valid()) {
                var curSubmitTime = new Date($.now());
		console.log('I am a valid form')
                // prevent the second submit if it is within 2 seconds of the first submit
                if (curSubmitTime - prevSubmitTime < 2000) {
                    console.log('A small time difference. So I am stopping')
                    e.preventDefault();
                }
                prevSubmitTime = new Date($.now());
            }
        });
    });
}

$(document).ready(function () {
    preventFromBeingDoubleSubmitted();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.js"></script>

<form id="myform">
    <input type="text" name="q" required="required" />
    <br />
    <input type="text" name="bar" required="required" />
    <br />
    <br />
    <input type="submit" />
</form>

  

谁能解释为什么有时会触发提交事件   紧接着一个接一个...有时不是这样吗?

我认为您已经回答了这个问题。您正在添加代码,以检查第一次单击提交按钮与第二次单击之间的时间差。如果存在时差,则停止第二个表单提交。

  

我永远都无法在e.preventDefault()上达到断点;

无法获得控制台的原因是,当您单击“提交”按钮时,您正在重定向离开该页面。这样便清除了控制台。如果要查看控制台,请使用ajax函数提交表单。返回时,您可能可以将页面重定向到某个地方。

  

是否将事件处理程序放入.each()中,影响其执行   行为?

不。它只是一个迭代器。不会影响提交功能。

我已经添加了一个指向jsfiddle的链接。在preventDefault之前添加警报将阻止页面暂时重定向。这将证明执行已发生。

http://jsfiddle.net/2vugwyfe/

答案 1 :(得分:4)

默认情况下提交表单时,导航到设置的action网址。在未明确设置的情况下,URL为当前页面。第一个提交呼叫将最终开始导航过程。在此期间,当前已加载的javascript代码将被卸载。这包括事件处理程序。因此,为什么会出现双重提交或不一致的矛盾。如果网络请求和其他页面处理操作URL发生的速度比您再次单击事件处理程序的速度要快,则不会再调用/到达您的断点,因为它们已被卸载。反之亦然,如果网络请求较慢,则可以使处理程序被调用并到达断点(如果尚未卸载)。

您说您不想永久禁用“提交”按钮,但是即使您将其禁用,表单提交也将导致页面更改,在您的示例中,这只会使用新的提交加载同一页面按钮,因为它有一个新页面,所以将不再被禁用。因此,从一开始它就永远不会真正消失。

现在,如果您的真实表单实际上未进行正常的表单提交,并且您正在使用ajax请求,Web套接字连接等功能,则可以在按钮之前将按钮设置为Disabled(或设置busy标志)请求并在ajax请求回调,Web套接字事件等中取消设置。

例如:

jQuery('form').on('submit',function(e){
  e.preventDefault();
  var fd = new FormData(this);
  jQuery('yourbutton').prop('disabled',true);
  fetch('url',{method:"post",body:fd}).then(()=>jQuery('yourbutton').prop('disabled',false));
});

答案 2 :(得分:1)

您的解决方案过于复杂。防止重复提交的最简单方法是禁用提交按钮。

示例:

var submittable = false;
$('form').submit(function (e) {
  if (!submittable) {
    e.preventDefault();
    var $this = $(this);
    var $submitButton = $this.find('button[type="submit"]');
    $submitButton.attr('disabled', true);

    if (CONDITION_SATISFIED) {
      submittable = true;
      $this.submit()
    } else {
      $submitButton.attr('disabled', false);
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<button type="submit">Submit</button>
</form>

答案 3 :(得分:1)

如果在进行e.preventDefault();之前添加$("form").valid(),将会看到抛出错误。

script.js:7 Uncaught TypeError: $(...).valid is not a function
at HTMLFormElement.<anonymous> (script.js:7)
at HTMLFormElement.dispatch (jquery.min.js:2)
at HTMLFormElement.y.handle (jquery.min.js:2)

首先看不到此错误,因为如果未执行任何其他操作,提交者实际上会更改页面(在这种情况下刷新页面)。

但是,通常,惯例是在提交表单后导航到另一个页面。 如果您仍然希望采用这种方法并限制提交的次数,建议将 submitted 状态保留在局部变量中,并根据服务器端的验证进行更改。

最后一件事..我不理解通过表单进行的迭代,因为您的HTML中只有一个-> $('form').each是没有用的。

答案 4 :(得分:0)

我知道您想要什么,但是您使它变得非常复杂。无需插入提交按钮,只需添加一个简单的div并在其上添加一个点击处理程序即可。

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="myform">
    <input type="text" name="myInput" />
    <div id="submit" onclick="myform_submit()" />
</form>

和:

function myform_submit() {
    if ($('#submit').hasClass('busy')) { return; }
    $('#submit').addClass('busy');

    // do the tasks then remove the `busy` class :
    $('#submit').removeClass('busy');
}

我只是展示这个想法,您可以做得更好。