如何才能正确捕获并重新启动表单提交事件?

Mat*_*att 20 javascript forms jquery event-handling

这可能不是您通常的"如何捕获表单提交事件?" 题.

我试图准确理解jQuery,vanilla Javascript和浏览器(IE/FF/Chrome/Safari/Opera)如何处理表单提交事件 - 以及它们之间的关系.(参见我的另一个问题.)经过数小时的谷歌搜索和实验,我仍然无法得出结论,无论是因为不和谐还是模糊.

我正在完成一个与网站表单集成的脚本,以便在AJAX请求返回之前无法提交表单.

理想的情况是:

  1. 用户填写表格
  2. 表单已提交 - 但除了我的之外,没有调用以前绑定的事件处理程序
  3. 我的处理程序发出API请求(当然是异步的)
  4. 用户确认API响应的验证结果
  5. 表单提交继续正常,自动,调用之前被抑制的其他处理程序

我目前的理解是:(这些可能是错的,如果是这样,请纠正我)

  • jQuery将表单提交事件处理程序绑定到提交按钮click事件
  • 直接在提交元素click事件上的事件处理程序(无论是在标记中onclick=""还是使用jQuery绑定)都会先执行
  • 接下来执行表单submit事件上的事件处理程序(无论是在标记中onsubmit=""还是使用jQuery绑定)
  • 调用$('[type=submit]').click()不会调用表单的submit事件,因此不会调用其处理程序
  • 调用$('form').submit()不会调用提交按钮的click事件,因此不会调用其处理程序
  • 然而,不知何故,单击提交按钮的用户最终会调用绑定到表单submit事件的处理程序...(但如上所述,调用单击提交按钮不会执行相同的操作)
  • 实际上,无论用户提交表单的任何方式(通过提交按钮或按Enter键),使用jQuery绑定到表单submit事件的处理程序都被调用...

现在,我是:

  1. 解除绑定处理程序与jQuery绑定到提交按钮的click事件,同时保留对它们的引用
  2. 将我自己的处理程序绑定到提交按钮的click事件,因此它首先执行
  3. 使用onclick=""onsubmit=""(在各自的元素上)绑定标记中的任何处理程序并使用jQuery重新绑定它们(因此它们在我的后面执行),然后将属性设置为null
  4. 重新绑定其处理程序(从步骤1开始),以便它们执行最后一次

实际上,这在我自己的测试中非常有效,所以我的事件处理程序首先触发(必要).

问题和我的问题:

我的处理程序首先触发,就像预期的那样(到目前为止).问题是我的处理程序是异步的,所以我必须禁止(preventDefault/stopPropagation/etc)表单submit或提交click调用它的按钮事件......直到API请求完成.然后,当API请求返回时,一切都是A-OK,我需要自动重新调用表单提交.但是由于我上面的观察,我如何确保所有事件处理程序都被触发,就像它是一个自然形式提交一样?

获取所有事件处理程序的最简洁方法是什么,首先放入我的事件,然后重新调用表单提交,以便以正确的顺序调用所有内容?

如果有的话,$('form').submit()和之间有什么区别$('form')[0].submit()?(与同为$('[type=submit]').click()$('[type=submit]')[0].click())

tl; dr,关于Javascript/jQuery/browser form-submit-event-handling的规范,清晰,一刀切的文档是什么?(我不是在寻找书籍推荐.)


一些解释:我正在尝试补偿购物车结帐页面中的大量Javascript,有时表单只在用户点击页面底部的按钮(不是提交按钮)时提交,或者有其他棘手的场景.到目前为止,它已经相当成功,它只是重新调用提交,这确实是问题所在.

use*_*654 6

使用jQuery绑定到表单的提交处理程序并阻止默认操作,然后,当您要提交表单时,直接在表单节点上触发它.

$("#formid").submit(function(e){
    // prevent submit
    e.preventDefault();

    // validate and do whatever else


    // ...


    // Now when you want to submit the form and bypass the jQuery-bound event, use 
    $("#formid")[0].submit();
    // or this.submit(); if `this` is the form node.

});
Run Code Online (Sandbox Code Playgroud)

通过调用submit表单节点的方法,浏览器执行表单提交而不触发jQuery的提交处理程序.


Mat*_*att 1

这就是我最终的做法,到目前为止,它在许多测试用例中都非常成功。我学到了很多关于事件的知识,特别是与 jQuery 相关的表单提交事件。我没有时间发布我收集的所有信息的综合百科全书,但现在就足够了:

这是用于SmartyStreets LiveAddress API jQuery 插件,该插件在用户离开页面之前验证地址。

最成功的方法是获取提交按钮的click事件。下面的代码片段可以在jquery.liveaddress.js文件中找到。它获取对尽可能多的事件处理程序的引用(jQuery、onclick——首先触发 onclick),将它们连根拔起,放下它自己的(submitHandler),并将其他事件处理程序分层在其之上。它在 TortugaRumCakes.com(结账)和 MedicalCareAlert.com(主页和结账)等网站以及许多其他网站上取得了成功。

完整代码位于GitHub上。这个特定的部分用于“单击”提交按钮,但类似的代码也用于处理表单提交。jQuery 的submit()函数似乎相当专有......但是这种处理既确保了即使.submit()在 jQuery 对象上以编程方式调用它也能被调用。

var oldHandlers, eventsRef = $._data(this, 'events');

// If there are previously-bound-event-handlers (from jQuery), get those.
if (eventsRef && eventsRef.click && eventsRef.click.length > 0)
{
    // Get a reference to the old handlers previously bound by jQuery
    oldHandlers = $.extend(true, [], eventsRef.click);
}

// Unbind them...
$(this).unbind('click');

// ... then bind ours first ...
$(this).click({ form: f, invoke: this }, submitHandler);

// ... then bind theirs last:
// First bind their onclick="..." handles...
if (typeof this.onclick === 'function')
{
    var temp = this.onclick;
    this.onclick = null;
    $(this).click(temp);
}

// ... then finish up with their old jQuery handles.
if (oldHandlers)
    for (var j = 0; j < oldHandlers.length; j++)
        $(this).click(oldHandlers[j].data, oldHandlers[j].handler);
Run Code Online (Sandbox Code Playgroud)