HTML表单上的默认提交按钮是如何确定的?

如果提交了表单,但不是通过任何特定的按钮,例如

  • 通过按输入
  • 使用JS中的HTMLFormElement.submit()

浏览器应该如何确定多个提交按钮(如果有的话)中的哪一个作为按下的按钮呢?

这在两个层面上很重要:

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

到目前为止,我的实验表明:

  • 当按输入时,Firefox、Opera和Safari使用表单中的第一个提交按钮
  • 当按输入时,IE使用第一个提交按钮或根本不使用,这取决于我还没能弄清楚的条件
  • 所有这些浏览器都不使用JS提交

标准是怎么说的?

如果有帮助的话,下面是我的测试代码(PHP只与我的测试方法相关,与我的问题本身无关)

<!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>
212410 次浏览

HTML 4并没有将其显式化。HTML 5 __abc0:

4.10.21.2隐式提交

form元素的默认按钮树的顺序中的第一个提交按钮,它的形式的主人就是那个form元素。

如果用户代理支持用户隐式提交表单 (例如,在某些平台上,点击“回车”;在文本中输入 控件是集中隐式提交表单),然后对一个 它的默认按钮激活的行为,而不是 禁用,必须导致用户代理触发click事件 默认按钮 . < / p >

如果你想影响哪个是“第一”;在保持视觉顺序的同时,你可以采取一些方法。

一个屏幕外、无法对焦的按钮。

.hidden-default {
position: absolute;
left: -9999px;
}
<form>
<input name="text">
<button name="submit" value="wanted" class="hidden-default" tabindex="-1"></button>
<button name="submit" value="not wanted">Not the default</button>
<button name="submit" value="wanted">Looks like the default</button>
</form>

Flexbox顺序:

.ordering {
display: inline-flex;
}


.ordering button {
order: 2;
}


.ordering button + button {
order: 1;
}
<form>
<input name="text">
<div class="ordering">
<button name="submit" value="wanted">First in document order</button>
<button name="submit" value="not wanted">Second in document order</button>
</div>
</form>

如果你通过JavaScript(即formElement.submit()或任何等价的东西)提交表单,那么提交按钮的没有一个被认为是成功的,并且它们的值都不包含在提交的数据中。(注意,如果你使用submitElement.click()提交表单,那么你引用的提交被认为是活动的;这并不属于你的问题范围,因为这里的提交按钮是明确的,但我认为我应该包括它给那些阅读第一部分并想知道如何通过JavaScript表单提交成功提交按钮的人。当然,表单的onsubmit处理程序仍然会以这种方式触发,而它们不会通过form.submit()触发,所以这是另一回事…)

如果表单是通过在非文本区域字段中按Enter提交的,那么实际上是由用户代理决定它在这里想要什么。的规格没有说任何关于在文本输入字段中使用输入键提交表单的内容(如果你选择一个按钮并使用空格或其他方式激活它,那么没有问题,因为特定的提交按钮被明确使用)。它只是说,当提交按钮被激活时,必须提交表单。甚至不要求在文本输入中按输入将提交表单。

我相信Internet Explorer会选择在源代码中首先出现的提交按钮;我有一种感觉,Firefox和Opera会选择标签索引最低的按钮,如果没有其他定义,就会退回到第一个定义的按钮。关于提交是否具有非默认值属性IIRC,也存在一些复杂性。

需要注意的一点是,这里所发生的事情并没有明确的标准,这完全是浏览器的心血来潮——所以无论你在做什么,尽量避免依赖任何特定的行为。如果你真的必须知道,你可能会发现各种浏览器版本的行为,但当我调查这个问题时,有一些相当复杂的条件(当然,随着新浏览器版本的变化),我建议你尽可能避免它!

从你的评论来看:

结果是,如果你有 多个表单提交给同一个 脚本,你不能依赖于提交

我在每个表单中放入<input type="hidden" value="form_name" />

如果使用JavaScript提交:将提交事件添加到表单,而不是将事件单击到按钮。精明的用户不会经常触碰鼠标。

我有一个有11个提交按钮的表单,当用户按输入时,它总是使用第一个提交按钮。我在别处读到过,在一个表单上有多个提交按钮不是一个好主意(糟糕的做法),最好的方法是将您想要的按钮作为默认按钮,作为表单上唯一的提交按钮。其他按钮应做成“;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是默认的,尽管您是通过编程方式提交表单和其他按钮,但mjsubmit例程将验证它们。

我认为这篇文章会帮助如果有人想用jQuery:

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

基本解决方案是:

$(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;
}
});
});

我的食谱:

<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>

如果没有一个按钮被“单击”,它将发送默认隐藏字段。

如果单击其中一个,它具有优先级,其值将被传递。

青云直上的回答几乎得到了它的钉子…但这里有一个简单的跨浏览器解决方案。

取这样的形式:

<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规范指出多个提交按钮是有效的,但忽略了用户代理应该如何处理它们的指导,所以浏览器制造商只能按照他们认为合适的方式来实现。我发现他们要么提交表单中的第一个提交按钮,要么在当前有焦点的表单字段之后提交下一个提交按钮。

不幸的是,简单地添加显示:没有;样式是行不通的,因为W3C规范指出任何隐藏元素都应该从用户交互中排除。所以把它藏在众目睽睽之下吧!

上面是我最终投入生产的解决方案示例。按enter键触发默认表单提交,即使在DOM中出现其他非默认值并在默认提交按钮之前也是如此。与显式用户输入的鼠标/键盘交互的额外好处,同时避免JavaScript处理程序。

注意:通过表单的标签将不会显示任何可视元素的焦点,但仍然会导致不可见按钮被选中。要避免此问题,只需相应地设置tabindex属性,并在不可见的提交按钮上省略tabindex属性。虽然将这些样式提升为!important似乎不合适,但它们应该防止任何框架或现有按钮样式干扰此修复。此外,那些内联样式绝对是糟糕的形式,但我们在这里证明概念…不编写产品代码。

我使用的另一种解决方案是在表单中只设置一个按钮,并伪造其他按钮。

这里有一个例子:

<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元素的样式设置为看起来像一个按钮。JavaScript侦听器观察跨度,并在单击后执行所需的操作。

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

HTML 4规范:

如果一个表单包含多个提交按钮,只有激活的

.提交按钮成功

这意味着如果有多个提交按钮且没有激活(单击),则没有一个提交按钮会成功。

我认为这是有道理的:

想象一个有多个提交按钮的巨大表单。在顶部,有一个“删除此记录”按钮,然后大量的输入紧随其后,在底部有一个“更新此记录”按钮。当用户在表单底部的字段中点击输入时,他/她永远不会怀疑他/她含蓄地点击了“删除此记录”。从上到下。

因此,我认为使用用户没有定义(点击)的第一个按钮或任何其他按钮都不是一个好主意。不过,浏览器当然也在这么做。

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

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

抱歉,当我写这个答案时,我想的是一般意义上的提交按钮。下面的答案不是关于多个type="submit"按钮,因为它只留下一个type="submit",并将另一个更改为type="button"。我把答案留在这里作为参考,以防帮助那些可以在他们的形式中改变type的人。

当你在一个表单中有多个提交按钮,并且用户按输入键从文本字段提交表单时,这段代码通过从按键事件调用表单上的提交事件来覆盖默认功能。代码如下:

$('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;
});

奇怪的是,无论第一个按钮是否可见,第一个按钮输入总是指向第一个按钮,例如使用jQuery show/hide()。添加属性.attr('disabled', 'disabled'),完全阻止接收输入提交按钮。例如,在记录对话框中调整插入/编辑+删除按钮的可见性时,这就是一个问题。我发现将编辑放在插入前面不那么生硬和简单:

<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');

我纠结于同样的问题,因为我在表单中间有一个提交按钮,可以重定向提交到另一个页面,就像这样:

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

当用户按下输入键时,单击的是这个按钮,而不是另一个提交按钮。

因此,我做了一些基本的测试,创建了一个带有多个提交按钮和不同可见性选项的表单,并创建了一个onclick事件来提醒哪个按钮被单击:https://jsfiddle.net/aqfy51om/1/

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

窗户

OS X

  • 谷歌Chrome 43
  • Safari 7.1.6

大多数浏览器都点击了第一个按钮,尽管应用了可见性选项除了ie和Safari浏览器,它点击了第三个按钮,这是“可见”。在一个“隐藏”;容器:

<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>

所以我的建议,也就是我自己的建议是:

如果你的表单有多个不同含义的提交按钮,那么在表单的开头包含一个默认动作的提交按钮,它可以是:

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

另一种选择可能是偏移按钮(仍然在开始)style="position: absolute; left: -9999px; top: -9999px;",刚刚在Internet Explorer中尝试过-工作,但我不知道它还能搞砸什么,例如打印..

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

超文本标记语言

<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 */
}

解释

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

演示

< a href = " http://codepen。io /戈德温/钢笔/ rLVKjm noreferrer“rel = > http://codepen.io/Godwin/pen/rLVKjm < / >

<form onsubmit="alert('submit');return false;">
<input name="username">
<input name="password" type="password">
<button onclick="if(document.activeElement === this){alert('button 1');}else{default_submit.click();}return false;">button 1</button>
<button onclick="if(document.activeElement === this){alert('button 2');}else{default_submit.click();}return false;">button 2</button>
<input id="default_submit" type="submit">
</form>

如果你从文本输入中按输入,那么按钮将不会聚焦。然后我们忽略这个点击,然后点击默认提交,但是如果你用鼠标点击按钮,它将被聚焦,然后我们应用这个点击。

演示:https://codepen.io/remon-reffat/pen/mdRaXbp