输入类型= "submit" ,onclick 处理程序调用 this.form.submit(),并且不返回任何值



编辑:在考虑回答问题之前,请仔细阅读整个问题。我不是在问在生产代码中使用内联事件处理程序的可取性,也不是在问实现我引用的文章所承诺的结果的最佳方式。这是一个关于Javascript语义和浏览器实现细节的问题,而不是关于最佳编码实践的问题

听起来像噩梦,对吧?

然而,我在网上发现了一些建议,主张采取这样的措施来防止双重提交表格:

<input type="submit" 
onclick="this.disabled=true;
this.value='Sending, please wait...';
this.form.submit();" />

抛开内联事件处理程序的弊端不谈,我在这里看到的问题是:

  1. 标签的类型为"submit",因此提交其包含表单是其默认行为
  2. onclick处理程序显式提交包含表单
  3. onclick处理程序不返回false以阻止默认行为(请参见1)

直觉上,我认为点击此项将与文章所声称的完全相反——即,提交两次表单,一次是作为显式submit()调用的结果,另一次是"submit"类型控件的未抑制默认行为。

另一方面,我写了一个很小的PHP脚本(如下),并在Firefox和Safari(目前是我唯一方便使用的浏览器)上进行了尝试,每次点击按钮只会写一个日志条目:

<html>
<head></head>
<body>
<?php
if (isset($_GET['action']) && $_GET['action'] == 'submit') {
$s = 'Got form submission at ' . time();
error_log($s);
echo $s;
}
else {
?>
<form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
method="post">
<input type="submit" 
onclick="this.disabled=true;
this.value='Sending, please wait...';
this.form.submit();" />
</form>
<?php
}
?>
</body>
</html>

那么,这两个浏览器真的在做"正确"的事情吗(其中"正确"是在一些我没有看到或没有仔细阅读的文档中定义的)——这意味着我对问题的分析是不完整或错误的?

或者,我的分析是正确的吗?这意味着观察到的单个提交是浏览器实现者放入特殊情况逻辑的结果,以避免天真的程序员?

更新:

为了从经验上测试@sourcecode的说法,即form.submit()方法是表单上的某种"第二次提交按钮",因此受HTML4规范第17.13.2节中规定的只能有一个"成功"提交按钮的规则的约束,我在我的PHP测试脚本中添加了一些内容:

<?php
if (isset($_GET['action']) && $_GET['action'] == 'submit') {
$s = 'Got form submission at ' . time() . ', tellme = ' . $_POST['tellme'];
error_log($s);
echo $s;
}
else {
?>
<form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
method="post">
<input type="hidden" id="tellme" name="tellme" value="0" />
<input type="submit" 
onclick="this.disabled=true;
this.value='Sending, please wait...';
this.form.submit();
document.getElementById('tellme')=1;" />
</form>
<?php
}
?>

在Firefox中,此代码生成单个错误日志条目:

时间戳收到表单提交,tellme=1

所做的表明方法调用在某种程度上被控件的内部事件驱动行为所取代。

此外,如果我在将tellme的值设置为1之后包括额外的return false;(从而防止点击事件传播,从而防止控件的固有行为),则单个错误日志条目为:

时间戳收到表单提交,tellme=0

意味着在这种情况下,提交是调用this.form.submit()的结果。

另一方面,当我在Safari中尝试相同的两个变体时,每个都会给我相同的单一错误日志条目:

时间戳收到表单提交,tellme=0

因此,在Safari的情况下,方法调用总是优先于事件驱动的提交——可能是因为它发生得更早。

是的。只是太棒了。://

进一步更新:我有机会在Windows NT 5.1上的IE 8.0上进行测试。

IE 8反映了Safari的行为,即form.submit()方法总是优先于偶数驱动的提交。

虽然这在今天几乎没有意义,但我也意识到,在运行OS X 10.4.11的更古老的PowerPC iMac上,我有一个古老的IE 5.22。这里有趣的历史琐事是,IE5的工作方式与IE8的工作方式完全相反:即使onclick处理程序末尾的return false;禁止点击事件传播,事件驱动的提交也总是取代form.submit()方法!(不过,我还没有深入研究这是一个bug还是一个功能。我还没有——也可能永远不会!——运行测试来确定它是在搞砸事件抑制,还是试图做一些"聪明"的事情。)

尽管如此,不管前后矛盾,两个IE都只提交一次。

我的初步结论(到目前为止,实际上相当坚定)是,"提交"类型的控件和DOMform.submit()方法之间的确切关系还没有定义好,浏览器实现者在没有任何明确指导的情况下,通常会做他们认为最好的事(例如,请参阅@Boris Zbarsky的回答)。

至少在Firefox、Safari和IE的情况下,它们的实现者预见到了事件和方法调用可能会竞争提交同一表单的可能性,并采取了一些步骤(尽管不同——几乎涵盖了所有步骤)来确保其中只有一个会成功。

(我仍然欢迎那些熟悉不同浏览器内部结构并能发表评论的人,或者那些使用我测试过的浏览器以外的浏览器加载了我的简单PHP脚本的人提供更多答案。)

Gecko(Firefox)当然会检测到多个提交,并在出现新提交时取消旧提交。请参阅中的mPendingSubmisson成员http://hg.mozilla.org/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.h以及在http://hg.mozilla.org/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.cpp(例如在nsHTMLFormElement::SubmitnsHTMLFormElement::PostHandleEvent中(后者是从提交控件的默认动作中调用的)。

就规范所说的内容而言,我不清楚规范是否一定是合理的,但它仍然存在http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#concept-表单提交,并表明两种提交都会发生,但由于"导航"算法的内部细节,后者可能会有效地取消前者。我申请了https://www.w3.org/Bugs/Public/show_bug.cgi?id=20580来整理规格。

这是w3组织的建议:

  • 如果表单包含多个提交按钮,则只有激活的提交按钮成功

    提交点击和本地JS表单也是如此。提交功能,只有"提交"被激活,而不是表单。提交功能。因为提交是主要的,JS函数是次要的。。
    你可以在这里了解更多链接

我想您需要使用stopPropogation()方法。理想情况下,您应该从onclick处理程序中调用一个函数,而不是将其全部内联。。请参阅另一个stackoverflow答案以获得完整的解释

千万不要在点击提交时执行脚本,并且一定不要提交表单!!!此外,如果您禁用该按钮,提交可能会停止!

如果文章中的代码能正常工作,那完全是运气好,我想许多浏览器都会进入一个禁用提交按钮和点击该禁用按钮时提交事件的竞争状态。

以下是一些在任何浏览器中都可以工作的内联建议

<form action="..." method="post" 
onsubmit="document.getElementById('subbut').innerHTML='Sending, please wait...'">
<span id="subbut"><input type="submit" /></span>
</form>

同样不引人注目:

window.addEventListener('load',function() {
document.getElementById('form1').addEventListener('submit', function(e) {
document.getElementById('subbut').innerHTML = 'Sending, please wait...';
})
})
<form action="..." method="post" id="form1">
<span id="subbut"><input type="submit" /></span>
</form>

最新更新