繁体   English   中英

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

[英]How is the default submit button on an HTML form determined?

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

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

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

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

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

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

form元素的默认按钮是树形顺序中的第一个提交按钮,其表单所有者是该form元素。

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

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 似乎不合适,但它们应该防止任何框架或现有按钮样式干扰此修复。 此外,这些内联样式绝对是糟糕的形式,但我们在这里证明了概念……而不是编写生产代码。

现在可以使用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 */
}

说明
使用 flex 框,我们还可以使用 CSS 规则: flex-direction: row-reverse使用display: flex的容器中元素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;
}
});
}); 

我有一个带有 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 例程会验证它们。 哈。

我遇到了同样的问题,因为我在中间有提交按钮,从中重定向提交到另一个页面,如下所示:

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

当用户按下回车键时,点击这个按钮而不是另一个提交按钮。

因此,我通过创建一个 from 与多个提交按钮和不同的可见性选项和 onclick 事件警告点击了哪个按钮来进行一些原始测试: https : //jsfiddle.net/aqfy51om/1/

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

视窗

  • 谷歌浏览器 43(来吧谷歌:D)
  • 火狐浏览器 38
  • 浏览器 11
  • 歌剧 30.0

操作系统

  • 谷歌浏览器 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;"包裹在容器中

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

当您在单个表单中有多个提交按钮并且用户按下 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;

});

奇怪的是,第一个按钮Enter总是转到第一个按钮,无论是否可见,例如使用 jquery show/hide() 添加属性.attr('disabled', 'disabled')完全阻止接收 Enter 提交按钮。 例如,在记录对话框中调整插入/编辑+删除按钮可见性时会出现问题。 我发现在Insert前放置Edit不那么笨拙和简单

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

从你的评论:

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

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

如果使用 javascript 提交:向表单添加提交事件,而不是向其按钮添加单击事件。 Saavy 用户不经常触摸他们的鼠标。

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

下面是一个例子:

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

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

HTML 4 规范

如果一个表单包含多个提交按钮,则只有激活的提交按钮才能成功。

这意味着给定超过 1 个提交按钮并且没有激活(点击),没有一个应该成功。

我认为这是有道理的:想象一个带有多个提交按钮的巨大表单。 在顶部,有一个“删除此记录”按钮,然后是大量输入,底部有一个“更新此记录”按钮。 用户在表单底部的字段中按 Enter 键永远不会怀疑他从顶部隐含地点击了“删除此记录”。

因此,我认为使用用户未定义(单击)的第一个按钮或任何其他按钮并不是一个好主意。 尽管如此,浏览器当然也在这样做。

我的食谱:

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

如果没有任何按钮被“点击”,它将发送默认的隐藏字段。

如果他们被点击,他们有偏好并且它的价值被传递。

编辑:对不起,在写这个答案时,我在考虑一般意义上的提交按钮。 下面的答案不是关于多个type="submit"按钮,因为它只留下一个type="submit"并将另一个更改为type="button" 我将答案留在这里作为参考,以防万一可以帮助可以更改表单type的人:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM