HTML 表单上的默认提交按钮是如何确定的?
Posted
技术标签:
【中文标题】HTML 表单上的默认提交按钮是如何确定的?【英文标题】:How is the default submit button on an HTML form determined? 【发布时间】:2010-10-29 20:20:11 【问题描述】:如果提交了表单但不是通过任何特定按钮,例如
按Enter 在 JS 中使用htmlFormElement.submit()
浏览器应该如何确定多个提交按钮中的哪一个(如果有)用作按下的按钮?
这在两个层面上很重要:
调用附加到提交按钮的onclick
事件处理程序
发回网络服务器的数据
到目前为止,我的实验表明:
当按下 Enter 时,Firefox、Opera 和 Safari 使用表单中的第一个提交按钮 当按下 Enter 时,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>
【问题讨论】:
【参考方案1】:HTML 4 没有明确说明。当前 HTML5 工作草案specifies that the first submit button must be the default:
@987654322@
元素的默认按钮是 第一个submit button in tree order 是谁的form owner 是那个@987654326@
元素。如果用户代理支持让用户提交表单 隐式(例如,在某些平台上按“enter”键 当文本字段被聚焦时隐式提交表单),然后 对于default button 已定义的表单这样做 activation behavior 必须使用户代理 run synthetic click activation steps 在那 default button.
【讨论】:
好的,这就是它应该做的。可以用吗? 我很高兴在 HTML5 中看到“隐含提交”。 也许会针对当前的情况进行更新?【参考方案2】:如果您通过 javascript(即formElement.submit()
或任何等效项)提交表单,则 没有 个提交按钮被认为是成功的,并且它们的值都不包含在提交的数据中。 (请注意,如果您使用submitElement.click()
提交表单,那么您引用的提交被认为是活动的;这并不真正属于您的问题范围,因为这里的提交按钮是明确的,但我认为我' d 为阅读第一部分并想知道如何通过 JavaScript 表单提交使提交按钮成功的人包括它。当然,表单的 onsubmit 处理程序仍然会以这种方式触发,而他们不会通过form.submit()
所以这是另一个水壶鱼...)
如果表单是通过在非文本区域字段中按 Enter 提交的,那么实际上由用户代理来决定它想要什么。 The specifications 不要说在文本输入字段中使用 Enter 键提交表单(如果您选择一个按钮并使用空格或其他方式激活它,那么就没有问题了明确使用了特定的提交按钮)。它只是说激活提交按钮时必须提交表单。甚至不需要在例如点击 Enter文本输入将提交表单。
我相信 Internet Explorer 会选择源中最先出现的提交按钮;我有一种感觉,Firefox 和 Opera 选择具有最低 tabindex 的按钮,如果没有定义其他内容,则回退到第一个定义的按钮。关于提交是否具有非默认值属性 IIRC 也有一些复杂性。
要带走的一点是,这里发生的事情没有明确的标准,这完全是浏览器的心血来潮 - 所以无论你在做什么,尽量避免依赖任何特定的行为。如果您真的必须知道,您可能会发现各种浏览器版本的行为,但是当我不久前对此进行调查时,有一些非常复杂的情况(当然会随着新的浏览器版本而改变),我会建议您尽可能避免!
【讨论】:
关于第 2 段:我的基本问题是任何规范中是否有任何关于“如果浏览器提供任何提交表单的方式而没有指定提交控件......”的内容。但我从大卫的回复中得知没有。我对 IE 的看法是,有时按下 Enter 会提交一个表单并且没有设置任何提交按钮。结果是,如果您有多个表单提交到同一个脚本,则不能依靠提交按钮来区分它们。这出现在我正在进行的项目中。 非常有用的第一段括号部分 - 谢谢。【参考方案3】:来自您的 cmets:
结果是,如果你有 多个表单提交到同一个 脚本,你不能依赖提交 按钮来区分它们。
我将<input type="hidden" value="form_name" />
放入每个表单中。
如果使用 JavaScript 提交:将提交事件添加到表单,而不是单击事件到其按钮。精明的用户不会经常触摸鼠标。
【讨论】:
确实,但这引出了这个问题:***.com/questions/541869/…【参考方案4】:我有一个带有 11 个提交按钮的表单,当用户按下 Enter 时,它总是使用第一个提交按钮。我在其他地方读到,在一个表单上有多个提交按钮不是一个好主意(不好的做法),最好的方法是将您想要的按钮作为默认按钮,作为表单上唯一的提交按钮。其他按钮应设为“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 例程会验证它们。
【讨论】:
坏主意。您的表单在禁用 JS 的情况下无法使用。 JS 的使用应该不显眼。 很少有浏览器默认关闭 JS,即使是 iPod 上的浏览器!在我引用的表格上,关闭 JS 会使它变得无用!这么多取决于 JS 的运行。 默认关闭与否,那些禁用 JS 的人不应该为了绕过这样一个愚蠢的小障碍而打开它。 什么样的表单有11个提交按钮?? (好奇心) 我看到验证不显眼的 Javascript 的最大原因是 obtrusive Javascript 往往很繁琐。我不确定如何限定我的想法,但是当我看到完全依赖 JS 的页面时,我也打赌我可以用我的 DOM 做一些棘手的事情,并在服务器上做一些意想不到的事情。【参考方案5】:如果有人想使用 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;
);
);
【讨论】:
jQuery.Event 始终具有其.wich
属性。也无需退回到 DOM 的 .keyCode
(或 .charCode
)。
这里关于 jQuery 的另一个问题是不必要的双重查询。由于不需要返回 true,另外,jQuery 版本在集成 Arjan 之前建议的缩减方面变得非常清晰和短。
我使用 keydown 而不是 keypress(避免等待 keyup),并且我在此函数的开头添加了 e.preventDefault();
以避免执行“真正的”默认按钮。效果很好。
链接已损坏 (404)。【参考方案6】:
我的食谱:
<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>
如果没有任何按钮被“点击”,它将发送默认隐藏字段。
如果一个被点击,它有偏好并且它的值被传递。
【讨论】:
但是这种行为是由标准规定的吗?是否可以信任浏览器来正确实现它? 好问题。我已经测试过它可以在所有 A 浏览器上工作(来自 yui 浏览器矩阵),它是我在现实生活中能得到的最一致的(不管标准指定什么) 我的错误,我更改了 type="hidden" 并且我没有注意到相同的“名称”值。 这在 IE11 或 Fx30 中对我不起作用。该值始终设置为隐藏值。 这在最新版本的 Chrome 和 Firefox 中没有所需的行为。 “action”参数always 包含用于隐式提交的值“login”。这将是一个优雅的解决方案,但不能依赖。【参考方案7】:Andrezj's answer 几乎搞定了……但这里有一个简单的跨浏览器解决方案。
采取这样的形式:
<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 规范表明多个提交按钮是有效的,但忽略了有关用户代理应如何处理它们的指导,因此浏览器制造商可以按照他们认为合适的方式实施。我发现他们要么提交表单中的第一个提交按钮,要么在当前具有焦点的表单字段之后提交下一个提交按钮。
不幸的是,简单地添加 display: none; 样式是行不通的,因为 W3C 规范指出任何隐藏元素都应该从用户交互中排除。所以把它藏起来吧!
以上是我最终投入生产的解决方案示例。按下回车键会触发默认表单提交,这是预期的行为,即使存在其他非默认值并且在 DOM 中的默认提交按钮之前也是如此。鼠标/键盘与显式用户输入交互的奖励,同时避免 JavaScript 处理程序。
注意:在表单中切换不会显示任何视觉元素的焦点,但仍会导致选择不可见按钮。为避免此问题,只需相应地设置 tabindex 属性并在不可见的提交按钮上省略 tabindex 属性。虽然将这些样式提升为 !important 似乎不合适,但它们应该防止任何框架或现有按钮样式干扰此修复。此外,这些内联样式绝对是糟糕的形式,但我们在这里证明了概念……而不是编写生产代码。
【讨论】:
谢谢。也偶然发现了 display: none 问题。除了最小化按钮,您还可以通过使用<div style="position: fixed; left: -1000px; top: -1000px />
将其移出页面。还有一件事需要关注:使用 CSS 将按钮从页面流中最小化或移开可能会带来 WAI 问题,因为屏幕阅读器仍会看到默认按钮。
感谢@James 的详细回答。
这对我有用,谢谢。我必须为按钮边框添加这个:无;让它完全消失
你可以将隐藏按钮的tabindex属性设置为-1
上面的<input/>
是干什么用的?【参考方案8】:
我使用的另一种解决方案是在表单中只使用一个按钮,并伪造其他按钮。
这是一个例子:
<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 侦听器会观察跨度并在单击后执行所需的操作。
它不一定适用于所有情况,但至少它很容易做到。
【讨论】:
禁用 JS 的用户的后备方案是什么? 禁用 JS 的用户将无法上网,就这么简单。【参考方案9】:来自HTML 4 specification:
如果一个表单包含多个提交按钮,只有激活的 提交按钮成功。
这意味着如果有多个提交按钮并且没有激活(单击),则没有一个应该是成功的。
我认为这是有道理的:
想象一个带有多个提交按钮的巨大表单。顶部有一个“删除这条记录”按钮,然后是大量输入,底部有一个“更新这条记录”按钮。在表单底部的字段中按 Enter 的用户永远不会怀疑他/她隐含地从顶部点击了“删除此记录”。
因此,我认为使用用户未定义(单击)的第一个按钮或任何其他按钮不是一个好主意。不过,浏览器当然会这样做。
【讨论】:
【参考方案10】:要确定按下回车键时按下的是哪个按钮,您可以将其标记为type="submit"
,而其他按钮则将它们标记为type="button"
。例如:
<input type="button" value="Cancel" />
<input type="submit" value="Submit" />
对不起,在写这个答案时,我在考虑一般意义上的提交按钮。下面的答案不是关于多个type="submit"
按钮,因为它只留下一个type="submit"
并将另一个更改为type="button"
。我将答案留在这里作为参考,以防有人可以更改其表单中的type
。
【讨论】:
键入“按钮”不会导致表单提交。它仅用于触发客户端脚本。 没错,这就是为什么当你按下回车键时浏览器会跳过它,而类型为“submit”的那个会被执行。例如,您可以使用带有“按钮”类型的按钮来执行任何其他操作。请删除反对票。 问题是关于多个提交按钮。 我的示例对多个提交按钮完全有效。类型为“提交”的那个是由浏览器确定为按下的那个(这就是问题所在)。然后使用另一个按钮,您可以将其用作提交按钮,也可以使用 JavaScript 事件,例如示例中的 onClick 事件。所以我的回答是相关的,不值得投反对票。请删除它。 如果您的意思是建议通过只让其中一个输入“提交”并使用 JavaScript 实现其他按钮来消除歧义,那么这是图形回复的副本,因此已经被认为是一个坏主意。【参考方案11】:当您在单个表单中有多个提交按钮并且用户按下 Enter 键从文本字段提交表单时,此代码会通过调用表单上的提交事件来覆盖默认功能从按键事件。这是代码:
$('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;
);
【讨论】:
简单并修复问题【参考方案12】:奇怪的是,无论是否可见,第一个按钮 Enter 总是转到第一个按钮,例如使用 jQuery show/hide()
。添加属性.attr('disabled', 'disabled')
完全阻止接收 Enter 提交按钮。例如,在记录对话框中调整 Insert/Edit+Delete 按钮的可见性时会出现问题。我发现将 Edit 放在 Insert 前面不那么老套和简单:
<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');
【讨论】:
【参考方案13】:我在同一个问题上苦苦挣扎,因为我在表单中间有一个提交按钮,它将提交重定向到另一个页面,如下所示:
<button type="submit" onclick="this.form.action = '#another_page'">More</button>
当用户按下 Enter 键时,该按钮被点击而不是另一个提交按钮。
所以我做了一些原始测试,创建了一个包含多个提交按钮和不同可见性选项的表单以及一个 onclick 事件,提醒点击了哪个按钮:https://jsfiddle.net/aqfy51om/1/
我用于测试的浏览器和操作系统:
窗口
Google Chrome 43(使用 Google 搜索:D) Mozilla Firefox 38 Internet Explorer 11 Opera30.0操作系统
谷歌浏览器 43 Safari7.1.6尽管应用了可见性选项除了 Internet Explorer 和 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>
所以我将自己使用的建议是:
如果您的表单有多个含义不同的提交按钮,则在表单开头包含一个具有默认操作的提交按钮,即:
-
完全可见
用
style="width: 0; height: 0; overflow: hidden;"
包装在一个容器中
另一种选择可能是偏移按钮(仍然在 from 的开头)style="position: absolute; left: -9999px; top: -9999px;"
,刚刚在 Internet Explorer 中尝试过 - 工作,但我不知道它还能搞砸什么,例如打印..
【讨论】:
【参考方案14】:现在可以使用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 */
说明
使用 Flexbox,我们可以通过使用 CSS 规则:flex-direction: row-reverse
来反转使用 display: flex
的容器中元素的顺序。这不需要 CSS 或隐藏元素。对于不支持 Flexbox 的旧浏览器,他们仍然可以得到一个可行的解决方案,但元素不会被反转。
演示
http://codepen.io/Godwin/pen/rLVKjm
【讨论】:
【参考方案15】:<form onsubmit="alert('submit');return false;">
<input name="username">
<input name="password" type="password">
<button onclick="if(document.activeElement === this)alert('button 1');elsedefault_submit.click();return false;">button 1</button>
<button onclick="if(document.activeElement === this)alert('button 2');elsedefault_submit.click();return false;">button 2</button>
<input id="default_submit" type="submit">
</form>
如果您在文本输入中按 Enter,则该按钮将不会成为焦点。然后我们忽略这个点击,而是点击默认提交,但是如果你用鼠标点击按钮,它会被聚焦,然后我们应用这个点击。
演示:https://codepen.io/remon-reffat/pen/mdRaXbp
【讨论】:
以上是关于HTML 表单上的默认提交按钮是如何确定的?的主要内容,如果未能解决你的问题,请参考以下文章