如何确定HTML表单上的默认提交button?

如果一个表单被提交,但不是由任何特定的button,如

  • Enter键
  • 在JS中使用HTMLFormElement.submit()

浏览器应该如何确定使用多个提交button中的哪一个button?

这在两个层面上是重要的:

  • 调用附加到提交button的onclick事件处理程序
  • 将数据发送回Web服务器

我迄今的实验表明:

  • 当按Enter键时 ,Firefox,Opera和Safari使用表单中的第一个提交button
  • 当按Enter时 ,IE使用第一个提交button或者根本不使用条件
  • 所有这些浏览器都没有使用JS提交

标准说什么?

如果有帮助,这里是我的testing代码(PHP只与我的testing方法有关,而不是我的问题本身)

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Test</title> </head> <body> <h1>Get</h1> <dl> <?php foreach ($_GET as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?> </dl> <h1>Post</h1> <dl> <?php foreach ($_POST as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?> </dl> <form name="theForm" method="<?php echo isset($_GET['method']) ? $_GET['method'] : 'get'; ?>" action="<?php echo $_SERVER['SCRIPT_NAME']; ?>"> <input type="text" name="method" /> <input type="submit" name="action" value="Button 1" onclick="alert('Button 1'); return true" /> <input type="text" name="stuff" /> <input type="submit" name="action" value="Button 2" onclick="alert('Button 2'); return true" /> <input type="button" value="submit" onclick="document.theForm.submit();" /> </form> </body></html> 

如果你通过Javascript提交表单(即formElement.submit()或任何等同的东西),那么没有一个提交button被认为是成功的,它们的值都不包括在提交的数据中。 (请注意,如果您使用submitElement.click()提交表单,那么您提交的提交文件被视为活动文件;这并不属于您的问题范围,因为这里提交button是明确的,但我认为我将它包含在阅读第一部分的人,并想知道如何通过JS表单提交成功提交button。当然,表单的提交处理程序仍然会以这种方式触发,而他们不会通过form.submit()这是另一个鱼的水壶…)

如果表单是在非textarea字段中按Enter键提交的,那么实际上是由用户代理来决定在这里要做什么。 在文本input字段中(如果您select一个button并使用空格或任何其他方式激活它,那么没有任何问题,因为具体的提交button是明确使用的), 规范没有说任何关于使用回车键提交表单。 它所说的是,当提交button被激活时,必须提交一个表单,甚至不要求在input文本时input提交表单。

我相信Internet Explorer会select源中第一个出现的提交button; 我有一种感觉,Firefox和Operaselecttabindex最低的button,回落到第一个定义,如果没有其他定义。 提交是否具有非默认值属性IIRC也有一些复杂性。

需要指出的是,对于这里发生的事情没有一个明确的标准,而完全是在浏览器的意外之处 – 尽可能无论你在做什么,都尽量避免依赖任何特定的行为。 如果你真的必须知道,你可能会发现各种浏览器版本的行为,但是当我调查了一段时间后,有一些相当复杂的条件(这当然会随着新的浏览器版本而改变),我会build议你尽可能避免它!

Andrezj几乎被钉上了…但这是一个简单的跨浏览器解决scheme。

采取这样的forms:

 <form> <input/> <button type="submit" value="some non-default action"/> <button type="submit" value="another non-default action"/> <button type="submit" value="yet another non-default action"/> <button type="submit" value="default action"/> </form> 

并重构为:

 <form> <input/> <button style="overflow: visible !important; height: 0 !important; width: 0 !important; margin: 0 !important; border: 0 !important; padding: 0 !important; display: block !important;" type="submit" value="default action"/> <button type="submit" value="some non-default action"/> <button type="submit" value="another non-default action"/> <button type="submit" value="yet another non-default action"/> <button type="submit" value="still another non-default action"/> <button type="submit" value="default action"/> </form> 

由于W3C规范指出多个提交button是有效的,但是对用户代理应该如何处理它们没有提供指导,所以浏览器制造商应该按照他们认为合适的方式来执行。 我发现他们会提交表单中的第一个提交button,或者在当前有焦点的表单域之后提交下一个提交button。

不幸的是,简单地添加一个显示风格:无; 将不起作用,因为W3C规范指出任何隐藏的元素应该从用户交互中排除。 所以把它隐藏在视线之内吧!

以上是我最终投入生产的解决scheme的一个例子。 按下Enter键会触发默认的表单提交行为与预期的一样,即使存在其他非默认值并且位于DOM中的默认提交button之前。 用于显式用户input的鼠标/键盘交互,同时避免使用JavaScript处理程序。

注意:通过窗体切换将不会显示任何视觉元素的焦点,但仍然会导致不可见的button被选中。 为避免此问题,只需相应地设置tabindex属性,并省略不可见提交button上的tabindex属性。 尽pipe将这些风格推广为重要,但它们应该防止任何框架或现有button样式干扰此修补程序。 此外,这些内联样式绝对是不好的forms,但我们在这里certificate了概念…不写代码。

HTML 4没有明确说明。 目前的HTML5工作草案规定,第一个提交button必须是默认的 :

form元素的默认button是树形次序中的第一个提交button ,其表单所有者是该form元素。

如果用户代理支持让用户隐式地提交表单(例如,在某些平台上按下“enter”键,而文本字段集中隐式提交表单),那么对于默认button具有定义的激活的表单行为必须使用户代理在该默认button上运行合成单击激活步骤 。

我觉得这个post会帮助,如果有人想用jQuery做到这一点:

http://greatwebguy.com/programming/dom/default-html-button-submit-on-enter-with-jquery/

基本的解决scheme是:

 $(function() { $("form input").keypress(function (e) { if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) { $('input[type=submit].default').click(); return false; } else { return true; } }); }); 

另一个我喜欢的是:

 jQuery(document).ready(function() { $("form input, form select").live('keypress', function (e) { if ($(this).parents('form').find('button[type=submit].default, input[type=submit].default').length <= 0) return true; if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) { $(this).parents('form').find('button[type=submit].default, input[type=submit].default').click(); return false; } else { return true; } }); }); 

我有一个有11个提交button的表单,当用户按下回车键时,它总是使用第一个提交button。 我在其他地方读到,在表单上有多个提交button不是一个好主意(不好的做法),最好的方法是将默认的button作为表单上唯一的提交button。 其他button应该被做成“TYPE = BUTTON”,并添加一个onClick事件来调用你自己在Javascript中的提交例程。 像这样的东西: –

 <SCRIPT Language="JavaScript"> function validform() { // do whatever you need to validate the form, and return true or false accordingly } function mjsubmit() { if (validform()) { document.form1.submit(); return true;} return false; } </SCRIPT> <INPUT TYPE=BUTTON NAME="button1" VALUE="button1" onClick="document.form1.submitvalue='button1'; return mjsubmit();"> <INPUT TYPE=BUTTON NAME="button2" VALUE="button2" onClick="document.form1.submitvalue='button2'; return mjsubmit();"> <INPUT TYPE=SUBMIT NAME="button3" VALUE="button3" onClick="document.form1.submitvalue='button3'; return validform();"> <INPUT TYPE=BUTTON NAME="button4" VALUE="button4" onClick="document.form1.submitvalue='button4'; return mjsubmit();"> 

在这里,button3是默认的,虽然你用其他button以编程方式提交表单,但是mjsubmit例程会validation它们。 HTH。

我在同一个问题上挣扎,因为我已经在redirect提交到另一个页面的中间提交button,如下所示:

 <button type="submit" onclick="this.form.action = '#another_page'">More</button> 

当用户按回车键,这个button被点击,而不是另一个提交button。

所以我做了一些简单的testing,通过创build一个从多个提交button和不同的可见性选项和onclick事件提醒哪个button被点击: https : //jsfiddle.net/aqfy51om/1/

我用于testing的浏览器和操作系统:

视窗

  • Google Chrome 43(来吧谷歌:D)
  • Mozilla Firefox 38
  • Internet Explorer 11
  • Opera 30.0

OSX

  • Google Chrome 43
  • Safari 7.1.6

大多数这些浏览器点击第一个button,尽pipe可见性选项应用exept IE和Safari ,点击第三个button,这是“隐藏”的容器内“可见”:

 <div style="width: 0; height: 0; overflow: hidden;"> <button type="submit" class="btn btn-default" onclick="alert('Hidden submit button #3 was clicked');">Hidden submit button #3</button> </div> 

所以我的build议,我要用我自己,是:

如果表单具有多个不同含义的提交button,则在表单的开始部分包含具有默认操作的提交button:

  1. 完全可见
  2. 包装在style="width: 0; height: 0; overflow: hidden;"的容器中

编辑另一个选项可能是偏移button(仍然在从开始) style="position: absolute; left: -9999px; top: -9999px;" ,只是试图在IE浏览器 – 工作,但我不知道还有什么可以搞砸了,例如打印..

从您的意见:

结果是,如果你有多个表单提交给同一个脚本,你不能依靠提交button来区分它们。

我将一个<input type="hidden" value="form_name" />放到每个表单中。

如果使用javascript进行提交,请将提交事件添加到表单中,而不是将事件单击到其button上。 Saavy用户不经常碰他们的鼠标。

奇怪的是,第一个button进入总是第一个button不pipe是否可见,例如使用jQuery的show/hide() 。 添加属性.attr('disabled', 'disabled')防止完全接收Enter提交button。 例如在logging对话框中调整插入/编辑+删除button的可见性是个问题。 我发现更less的hackish和简单的放置在插入前的编辑

 <button type="submit" name="action" value="update">Update</button> <button type="submit" name="action" value="insert">Insert</button> <button type="submit" name="action" value="delete">Delete</button> 

并使用JavaScript代码:

 $("#formId button[type='submit'][name='action'][value!='insert']").hide().attr('disabled', 'disabled'); $("#formId button[type='submit'][name='action'][value='insert']").show().removeAttr('disabled'); 

现在可以使用flexbox来解决这个问题了:

HTML

 <form> <h1>My Form</h1> <label for="text">Input:</label> <input type="text" name="text" id="text"/> <!-- Put the elements in reverse order --> <div class="form-actions"> <button>Ok</button> <!-- our default action is first --> <button>Cancel</button> </div> </form> 

CSS

 .form-actions { display: flex; flex-direction: row-reverse; /* reverse the elements inside */ } 


使用弹性框,我们可以通过使用CSS规则来反转使用display: flex的容器中元素的顺序: flex-direction: row-reverse 。 这不需要CSS或隐藏的元素。 对于不支持flexbox的旧浏览器,他们仍然可以得到可行的解决scheme,但是这些元素不会被颠倒过来。

演示
http://codepen.io/Godwin/pen/rLVKjm

我的食谱:

 <form> <input type=hidden name=action value=login><!-- the magic! --> <input type=text name=email> <input type=text name=password> <input type=submit name=action value=login> <input type=submit name=action value="forgot password"> </form> 

如果没有button被点击,它将发送默认的隐藏字段。

如果他们被点击,他们有偏好,它的价值是通过的。

我使用的另一个解决scheme是在窗体中只有一个button,并假冒其他button。

这是一个例子:

 <form> <label for="amount">Amount of items</label> <input id="amount" type="text" name="amount" /> <span id="checkStock" class="buttonish">Check stock</span> <button type="submit" name="action" value="order">Place order</button> </form> 

然后,我将span元素devise为一个button。 JS侦听器观察跨度,并执行一次点击所需的操作。

不一定适用于所有情况,但至less这很容易做到。

从HTML 4规范 :

如果表单包含多个提交button,则只有激活的提交button成功。

这意味着给定多于1个提交button而没有激活(点击),没有任何应该成功。

我认为这是有道理的:想象一个包含多个提交button的巨大表单。 在顶部,有一个“删除此logging”button,然后有很多input,底部有一个“更新此logging”button。 用户在窗体底部的字段中按下input时,将永远不会怀疑他从顶部隐式地击中了“删除此logging”。

因此,我认为使用第一个或其他任何button(用户不定义(单击)一个button)并不是一个好主意。 不过,浏览器当然也在这样做。

当您在一个表单中有多个提交button,并且用户按下ENTER键从文本字段提交表单时,此代码将通过从按键事件调用表单上的提交事件来覆盖默认function。 这是代码:

 $('form input').keypress(function(e){ if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){ $(e.target).closest('form').submit(); return false; } else return true; }); 

编辑:对不起,当写这个答案我一直在考虑提交button在一般意义上。 下面的答案不是关于多个type="submit"button,因为它只留下一个type="submit" ,改变另一个type="button" 。 我将答案留在这里作为参考,以帮助可以改变forms的人:

要确定按下回车键时按下了哪个button,可以用type="submit"来标记它,其他button用type="button"标记它们。 例如:

 <input type="button" value="Cancel" /> <input type="submit" value="Submit" />