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

IT技术 javascript html cross-browser standards
2021-01-16 04:59:20

如果表单已提交但未通过任何特定按钮提交,例如

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

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

这在两个层面上具有重要意义:

  • 调用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>
6个回答

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

如果表单是通过在非 textarea 字段中按 Enter 提交的,那么实际上取决于用户代理来决定它在这里想要什么。规范没有说明Enter在文本输入字段中使用提交表单的任何内容(如果您使用 Tab 键切换到按钮并使用空格或其他方式激活它,那么没有问题,因为该特定提交按钮已明确使用)。它只是说当激活提交按钮时必须提交表单。甚至不需要Enter输入例如文本输入将提交表单。

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

要带走的一点是,这里发生的事情没有定义的标准,这完全是浏览器的一时兴起 - 所以无论你在做什么,尽量避免依赖任何特定的行为。如果您真的必须知道,您可能会发现各种浏览器版本的行为,但是当我不久前对此进行调查时,发现了一些非常复杂的情况(当然,这些情况会随着新浏览器版本的变化而变化),我会建议您尽可能避免它!

关于第 2 段:我的基本问题是,在任何规范中是否有任何说明“如果浏览器提供任何提交表单的方法而不指定提交控件......”。但我从大卫的回答中得知没有。我对 IE 的看法是,有时按 Enter 会提交一个表单并且没有设置任何提交按钮。结果是,如果您有多个表单提交到同一个脚本,则不能依靠提交按钮来区分它们。这出现在我正在从事的项目中。
2021-03-19 04:59:20
非常有用的第一段括号部分 - 谢谢。
2021-04-03 04:59:20

HTML 4 没有明确说明。当前的 HTML5 工作草案指定第一个提交按钮必须是默认的

一个form元素的默认按钮是第一个提交按钮树形结构顺序,其所属表单form元素。

如果用户代理支持让用户隐式提交表单(例如,在某些平台上,在文本字段聚焦时点击“输入”键隐式提交表单),则为默认按钮具有定义 激活的表单执行此操作行为必须导致用户代理 在该默认按钮运行合成点击激活步骤

我很高兴在 HTML5 中看到“暗示提交”。
2021-03-18 04:59:20
好的,这就是它应该做的。我可以用吗?
2021-03-19 04:59:20
也许更新当前的事态?
2021-03-28 04:59:20

Andrezj 的回答几乎一针见血……但这里有一个简单的跨浏览器解决方案。

采取这样的形式:

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

不幸的是,简单地添加一个显示样式:none; 将不起作用,因为 W3C 规范指示应从用户交互中排除任何隐藏元素。所以把它藏在显眼的地方吧!

以上是我最终投入生产的解决方案示例。按回车键触发默认表单提交是预期的行为,即使存在其他非默认值并且在 DOM 中的默认提交按钮之前也是如此。鼠标/键盘与显式用户输入交互的奖励,同时避免 JavaScript 处理程序。

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

这对我有用,谢谢。我不得不为按钮边框添加这个:无;让它完全消失
2021-03-25 04:59:20
那上面<input/>什么用?
2021-03-29 04:59:20
谢谢@James 的详细回答。
2021-04-08 04:59:20
谢谢。偶然发现显示器:也没有问题。除了最小化按钮之外,您还可以通过用<div style="position: fixed; left: -1000px; top: -1000px />. 还有一件事需要关注:使用 CSS 将按钮从页面流中最小化或移开可能会带来 WAI 问题,因为屏幕阅读器仍将看到默认按钮。
2021-04-09 04:59:20
您可以将隐藏按钮的 tabindex 属性设置为 -1
2021-04-09 04:59:20

现在可以使用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,我们可以颠倒容器中元素的顺序,该容器display: flex也使用 CSS 规则:flex-direction: row-reverse这不需要 CSS 或隐藏元素。对于不支持 Flexbox 的旧版浏览器,他们仍然可以获得可行的解决方案,但元素不会被反转。

演示

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

我认为如果有人想用 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 的另一个问题是不必要的双重查询。由于不需要返回 true,此外,jQuery 版本在整合之前由 Arjan 建议的减少方面变得非常清晰和简短。
2021-03-25 04:59:20
我使用 keydown 而不是 keypress(避免等待 keyup)并且我添加e.preventDefault();到这个函数的开头以避免执行“真正的”默认按钮。效果很好。
2021-03-30 04:59:20
链接已断开 (404)。
2021-04-06 04:59:20
jQuery.Event总是有它的.wich属性。也无需退回到 DOM .keyCode(或.charCode就此而言)。
2021-04-11 04:59:20