Javascript 如何正确捕获并重新触发表单提交事件,保证?
这可能不是您通常提出的“如何捕获表单提交事件?”问题 我试图准确地理解jQuery、vanilla Javascript和浏览器(IE/FF/Chrome/Safari/Opera)是如何处理表单提交事件的,以及它们之间的关系。()经过几个小时的谷歌搜索和实验,我仍然无法得出结论,要么是因为不一致,要么是因为含糊不清 我正在完成一个与网站表单集成的脚本,以便在AJAX请求返回之前无法提交表单 理想情况下:Javascript 如何正确捕获并重新触发表单提交事件,保证?,javascript,jquery,forms,event-handling,Javascript,Jquery,Forms,Event Handling,这可能不是您通常提出的“如何捕获表单提交事件?”问题 我试图准确地理解jQuery、vanilla Javascript和浏览器(IE/FF/Chrome/Safari/Opera)是如何处理表单提交事件的,以及它们之间的关系。()经过几个小时的谷歌搜索和实验,我仍然无法得出结论,要么是因为不一致,要么是因为含糊不清 我正在完成一个与网站表单集成的脚本,以便在AJAX请求返回之前无法提交表单 理想情况下: 用户填写表格 表单已提交,但除了我的事件处理程序外,没有调用以前绑定的事件处理程序 我的处
- 直接在submit元素
上的事件处理程序首先执行事件(无论是在标记中,如click
,还是使用jQuery绑定)onclick=“”
- 接下来执行表单
事件上的事件处理程序(无论是在submit
这样的标记中还是使用jQuery绑定)onsubmit=”“
- 调用
不会调用表单的$('[type=submit]')。单击()
事件,因此不会调用其处理程序submit
- 调用
不会调用submit按钮的$('form').submit()
单击事件,因此不会调用其处理程序
- 然而,不知何故,用户单击submit按钮最终调用绑定到表单的
事件的处理程序。。。(但如上所述,调用“提交”按钮上的“单击”并不起同样的作用)submit
- 事实上,用户提交表单的任何方式(通过提交按钮或按Enter键),与jQuery绑定到表单
事件的处理程序都被称为submit
click
事件,同时保留对它们的引用click
事件,因此它首先执行onclick=“”
和onsubmit=“”
(在它们各自的元素上)在标记中绑定任何处理程序,并使用jQuery重新绑定它们(因此它们在我之后执行),然后将属性设置为null
submit
或submit按钮单击调用它的事件。。。直到API请求完成。然后,当API请求返回时,一切正常,我需要重新调用表单submit自动提交。但是由于我上面的观察,我如何确保所有的事件处理程序都像自然表单一样被触发呢
获取所有事件处理程序、首先放置我的事件处理程序、然后重新调用表单submit以便按正确顺序调用所有事件处理程序的最干净方法是什么
如果有的话,$('form').submit()和$('form')[0].submit()之间有什么区别?(对于$('[type=submit]')也是如此。单击()
和$('[type=submit]')[0]。单击()
tl;dr,关于Javascript/jQuery/browser表单提交事件处理的规范、清晰、一刀切的文档是什么?(我不是在寻找书籍推荐。)
一些解释:我试图弥补购物车结帐页面中的大量Javascript,有时候只有当用户单击页面底部的按钮(而不是提交按钮)时才提交表单,或者存在其他棘手的场景。到目前为止,它相当成功,只是重新调用了提交,这才是真正的问题。使用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的提交处理程序的情况下进行表单提交。这两个函数可能会帮助您在jQuery队列的前端绑定事件处理程序。您仍然需要剥离内联事件处理程序(onclick
,onsubmit
),并使用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
}
});
必须有很多方法来解决这个问题——这里有一个
它将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');
});
});
});
(使用模拟ajax)
作为额外的奖励,可以使自定义队列中的任何处理程序抑制任何/所有后续处理程序,和/或抑制表单提交。只需根据需要选择合适的模式:
模式1:
仅当前面的所有处理程序未拒绝def时才执行其操作。并且可以抑制模式1和模式2的所有后续处理程序
$("#myForm").on(formSubmitQueue, function(e, def) {
if(def.state() !== 'rejected') {
//actions as required here
if (expression) {
def.reject();
}
}
});
$("#myForm").on(formSubmitQueue, function(e, def) {
//actions as required here
if (expression) {
def.reject();
}
});
模式2:
仅当前面的所有处理程序未拒绝def时才执行其操作。但这并不是一个好主意
$("#myForm").on(formSubmitQueue, function(e, def) {
//actions as required here
if (expression) {
def.reject();
}
});
$("#myForm").on(formSubmitQueue, function(e, def) {
//actions as required here
});
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);