我怎样才能正确地捕捉和再火的形式提交事件,保证?(How can I correctly captu

2019-08-01 16:17发布

这可能不是你平常的“我如何捕获形式提交事件?” 题。

我试图精确地了解如何表单提交事件的jQuery,香草的Javascript处理,并且浏览器(IE / FF / Chrome浏览器/ Safari浏览器/歌剧) -和它们之间的关系。 ( 见我的其他问题。 )谷歌搜索后和实验的时间,我还是不能得出一个结论,要么是因为不和或含糊不清的。

我完成了一个脚本,以使表格无法提交,直到AJAX请求回来的网站形式的集成。

理想的情况是:

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

我现在的理解是:(这些可能是错的,请若有指正)

  • jQuery的结合形式提交事件处理程序的提交按钮click事件
  • 事件处理程序上直接提交元件click事件(是否在像标记onclick=""或使用jQuery绑定)首先被执行
  • 在表格上的事件处理程序submit事件(是否在像标记onsubmit=""或使用jQuery结合的)下一个被执行
  • 调用$('[type=submit]').click()不调用表单的submit事件,所以它的处理程序不会被调用
  • 调用$('form').submit()不调用提交按钮的click事件,所以它的处理程序不会被调用
  • 然而不知何故,即点击提交按钮的用户最终绑定到窗体的调用处理程序submit事件......(但正如上面提到的,提交按钮调用点击不这样做)
  • 事实上, 任何方式向用户提交表单(通过提交按钮或者按回车键),在形式与jQuery绑定处理程序submit事件被称为...

现在,我是:

  1. 使用jQuery绑定到提交按钮的解除绑定处理click事件,同时保持对它们的引用
  2. 结合我自己的处理程序提交按钮的click事件,所以它执行第一
  3. 以在标记结合的任何处理程序使用onclick=""onsubmit="" (在它们各自的元素)和使用jQuery(这样它们矿之后执行)重新结合它们,然后设定的属性,以null
  4. 再结合自己的处理程序(步骤1),所以他们最后执行

其实,这一直是我自己的测试非常有效,让我的事件处理程序触发第一(必要的)。

这个问题,我的问题:

我的处理程序便会启动第一,正如预期(至今)。 问题是,我的处理是异步的,所以我必须抑制(的preventDefault / stopPropagation /等)的形式submit或提交按钮click那个调用它......直到API请求完成事件。 然后,当API请求回来,一切都OK,我需要重新调用的形式自动提交。 但是因为我的观察之上的,我怎么确保就好像它是一个自然的形式提交所有的事件处理程序?

什么是抓住他们的所有事件处理程序最清晰的方式,放矿,再重新调用的形式提交,使一切被称为在其正确的顺序?

又有什么区别,如果任何一个, $('form').submit()$('form')[0].submit() (与同为$('[type=submit]').click()$('[type=submit]')[0].click()

TL;博士 ,什么是规范的,明确的,一个尺寸适合所有关于JavaScript / jQuery的/浏览器表单提交事件处理文档? (我不是在找书的建议。)


一些解释:我试图弥补的购物车结帐页面很多的Javascript,有时在那里的形式提交仅当用户单击该按钮(不提交按钮),在页面的底部,或有其他棘手的场景。 到目前为止,它已经相当成功,它只是重新调用提交的真正问题。

Answer 1:

绑定到表单的使用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.

});

通过调用submit表单节点的方法,该浏览器的形式提交,而不会触发jQuery的提交处理。



Answer 2:

这两个功能可以帮助您在了jQuery队列的前面,结合事件处理程序。 你仍然需要剥去联事件处理程序( onclickonsubmit ),并使用jQuery重新绑定它们。

// prepends an event handler to the callback queue
$.fn.bindBefore = function(type, fn) {

    type = type.split(/\s+/);

    this.each(function() {
        var len = type.length;
        while( len-- ) {
            $(this).bind(type[len], fn);

            var evt = $.data(this, 'events')[type[len]];
            evt.splice(0, 0, evt.pop());
        }
    });
};

// prepends an event handler to the callback queue
// self-destructs after it's called the first time (see jQuery's .one())
$.fn.oneBefore = function(type, fn) {

    type = type.split(/\s+/);

    this.each(function() {
        var len = type.length;
        while( len-- ) {
            $(this).one(type[len], fn);

            var evt = $.data(this, 'events')[type[len]];
            evt.splice(0, 0, evt.pop());
        }
    });
};

绑定执行Ajax调用提交处理程序:

$form.bindBefore('submit', function(event) {
    if (!$form.hasClass('allow-submit')) {
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();

        // perform your ajax call to validate/whatever
        var deferred = $.ajax(...);
        deferred.done(function() {
            $form.addClass('allow-submit');
        });

        return false;
    } else {
        // the submit event will proceed normally
    }
});

绑定一个独立的处理程序,以阻止在点击事件[type="submit"]直到你准备:

$form.find('[type="submit"]').bindBefore('click', function(event) {
    if (!$form.hasClass('allow-submit')) {
        // block all handlers in this queue
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();
        return false;
    } else {
        // the click event will proceed normally
    }
});


Answer 3:

必须有解决这个许多方面 - 这里有一个。

在自定义事件队列它让你的Ajax功能(A)与所有其他(B,C,d等)分离出来,通过将只有A标准“提交”队列,B,C,d等。 这避免棘手阴谋在其他方面必要使B,C,d等依赖于A的异步响应。

$(function(){
    var formSubmitQueue = 'formSubmitQueue';

    //Here's a worker function that performs the ajax.
    //It's coded like this to reduce bulk in the main supervisor Handler A.
    //Make sure to return the jqXHR object that's returned by $.ajax().
    function myAjaxHandler() {
        return $.ajax({
            //various ajax options here
            success: function(data, textStatus, jqXHR) {
                //do whatever is necessary with the response here
            },
            error: function(jqXHR, textStatus, errorThrown) {
                //do whatever is necessary on ajax error here
            }
        });
    }

    //Now build a queue of other functions to be executed on ajax success.
    //These are just dummy functions involving a confirm(), which allows us to reject the master deferred passed into these handlers as a formal variable.
    $("#myForm").on(formSubmitQueue, function(e, def) {
        if(def.state() !== 'rejected') {
            if (!confirm('Handler B')) {
                def.reject();
            }
        }
    }).on(formSubmitQueue, function(e, def) {
        if(def.state() !== 'rejected') {
            if (!confirm('Handler C')) {
                def.reject();
            }
        }
    }).on(formSubmitQueue, function(e, def) {
        if(def.state() !== 'rejected') {
            if (!confirm('Handler D')) {
                def.reject();
            }
        }
    });

    $("#myForm").on('submit', function(e) {
        var $form = $(this);
        e.preventDefault();
        alert('Handler A');
        myAjaxHandler().done(function() {
            //alert('ajax success');
            var def = $.Deferred().done(function() {
                $form.get(0).submit();
            }).fail(function() {
                alert('A handler in the custom queue suppressed form submission');
            });
            //add extra custom handler to resolve the Deferred.
            $form.off(formSubmitQueue+'.last').on(formSubmitQueue+'.last', function(e, def) {
                def.resolve();
            });
            $form.trigger(formSubmitQueue, def);
        }).fail(function() {
            //alert('ajax failed');
        });
    });
});

DEMO (带模拟AJAX)

作为额外的奖励 ,任何自定义队列中的处理,可制成压制任何/所有后续处理程序和/或抑制形式提交。 只要选择合适的模式取决于真实需要什么:

模式1:

执行动作只有当所有前面的处理程序没有DEF拒绝。 并能抑制模式1和模式2的所有后续处理。

$("#myForm").on(formSubmitQueue, function(e, def) {
    if(def.state() !== 'rejected') {
        //actions as required here
        if (expression) {
            def.reject();
        }
    }
});

模式2:

执行动作只有当所有前面的处理程序没有DEF拒绝。 但不抑制如下处理。

$("#myForm").on(formSubmitQueue, function(e, def) {
    if(def.state() !== 'rejected') {
        //actions as required here
    }
});

模式3:

无条件地执行其行动,但仍可以抑制模式1和模式2的所有后续处理。

$("#myForm").on(formSubmitQueue, function(e, def) {
    //actions as required here
    if (expression) {
        def.reject();
    }
});

模式4:

无条件地执行其行动,并没有打压下处理。

$("#myForm").on(formSubmitQueue, function(e, def) {
    //actions as required here
});

笔记:

  • 为了立即提交表单,而不处理队列中的其余部分推迟可能在这些处理程序来解决。 但在一般情况下,推迟将由“去年”处理程序添加到队列动态队列被触发(在处理程序后)之前得到解决。
  • 在演示中,所有的处理程序是模式1。


Answer 4:

以下是我最后做这一点,就已经很成功至今在众多的测试案例。 我学到了非常有关事件,特别是表单提交的事件,有关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);


文章来源: How can I correctly capture and re-fire the form submit event, guaranteed?