【问题标题】:How is the default submit button on an HTML form determined?HTML 表单上的默认提交按钮是如何确定的?
【发布时间】: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>

【问题讨论】:

    标签: javascript html cross-browser standards


    【解决方案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 提交:将提交事件添加到表单,而不是单击事件到其按钮。精明的用户不会经常触摸鼠标。

    【讨论】:

    【解决方案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/

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

        窗口

        操作系统

        • 谷歌浏览器 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>
        

        所以我将自己使用的建议是:

        如果您的表单有多个含义不同的提交按钮,则在表单开头包含一个具有默认操作的提交按钮,即:

        1. 完全可见
        2. 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');}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>
            

            如果您在文本输入中按 Enter,则该按钮将不会成为焦点。然后我们忽略这个点击,而是点击默认提交,但是如果你用鼠标点击按钮,它会被聚焦,然后我们应用这个点击。

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

            【讨论】:

              猜你喜欢
              • 2012-01-22
              • 2010-12-30
              • 1970-01-01
              • 1970-01-01
              • 2013-02-27
              • 2016-02-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多