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:

结果是,如果你有 多个表单提交到同一个 脚本,你不能依赖提交 按钮来区分它们。

我将&lt;input type="hidden" value="form_name" /&gt; 放入每个表单中。

如果使用 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 问题。除了最小化按钮,您还可以通过使用&lt;div style="position: fixed; left: -1000px; top: -1000px /&gt; 将其移出页面。还有一件事需要关注:使用 CSS 将按钮从页面流中最小化或移开可能会带来 WAI 问题,因为屏幕阅读器仍会看到默认按钮。 感谢@James 的详细回答。 这对我有用,谢谢。我必须为按钮边框添加这个:无;让它完全消失 你可以将隐藏按钮的tabindex属性设置为-1 上面的&lt;input/&gt; 是干什么用的?【参考方案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 表单上的默认提交按钮是如何确定的?的主要内容,如果未能解决你的问题,请参考以下文章

HTML 表单上的多个提交按钮 - 将一个按钮指定为默认按钮 [重复]

如何禁止按回车键提交表单

如何禁止按回车键提交表单

HTML,如何按回车提交表单

如何确定 jQuery 表单插件中的活动提交按钮?

如何在 WebBrowser 中以编程方式提交没有提交按钮的表单