HTML表单中的多个提交按钮 - 指定一个按钮作为默认按钮

141

我有一个表单,其中包含三个提交按钮,如下所示:

<input type="submit" name="COMMAND" value="&lsaquo; Prev">
<input type="submit" name="COMMAND" value="Save">
<input type="reset"  name="NOTHING" value="Reset">
<input type="submit" name="COMMAND" value="Next &rsaquo;">
<input type="button" name="NOTHING" value="Skip &rsaquo;" onclick="location = 'yada-yada.asp';">

按钮行包含提交、重置和JavaScript按钮。按钮的顺序可能会更改,但在任何情况下,保存按钮都位于上一步和下一步按钮之间。

问题在于,当用户按Enter键提交表单时,POST变量"COMMAND"包含"Prev",这是表单上第一个提交按钮的默认值。然而,我希望用户通过Enter按钮提交表单时触发"Next"按钮。这有点像将其设置为默认提交按钮,尽管它之前还有其他按钮。


4
如果你(或其他人)有兴趣,我曾经遇到过类似问题,并使用了这个 CSS 技巧(https://dev59.com/9GfWa4cB1Zd3GeqPiZV9),将我的主提交按钮放置在表单顶部,但将其显示在表单底部,容器是唯一需要固定尺寸的元素(`padding-bottom` 为主提交按钮或包含元素的高度),因此它可以根据表单内容轻松动态增长。 - topherg
1
如果你正在使用ASP.NET WebForms作为服务器端,可以将其包含在<ASP:Panel Defaultbutton="btnThatShouldBeDefault">中。这会自动生成JavaScript代码,根据插入符号的位置使正确的按钮成为默认按钮。 - Ross Presser
可能是 在HTML表单中使用多个提交按钮 的重复问题。 - Peter Mortensen
9个回答

87

第一个按钮总是默认的,无法更改。虽然您可以尝试使用JavaScript进行修复,但在没有脚本的浏览器中,表单将出现意外行为,并且还有一些可用性/可访问性角落案例需要考虑。例如,Zoran链接的代码将在<input type="button">中按Enter键意外提交表单,这通常不会发生,并且不会捕获IE在表单中的其他非字段内容上按Enter键提交表单的行为。因此,如果您单击表单中的<p>中的某些文本并按Enter键,则将提交错误的按钮...特别危险的是,如果像该示例中所给出的那样,真正的默认按钮是“删除”!

我的建议是忘记使用脚本技巧重新分配默认值。随着浏览器的发展而流行,并将默认按钮放在第一位。如果您无法通过布局来获取所需的屏幕顺序,则可以通过在源代码中首先添加一个虚拟不可见按钮,并具有与要设置为默认的按钮相同的名称/值来实现。

<input type="submit" class="defaultsink" name="COMMAND" value="Save" />

.defaultsink {
    position: absolute; left: -100%;
}

(注意:使用定位将按钮推出屏幕,因为display: nonevisibility: hidden对于按钮是否被视为默认选项以及是否提交具有浏览器变量副作用。)


6
跟随您的指示,我发现以下方法适用于我:在 <form> 标记下方放置 <input type="submit" name="..." value="..." style="display:none;" />,这会复制后面出现的可见按钮。 - Graham Klyne
11
第一个按钮是默认的,但它可以更改 :-). 对于非默认按钮,请使用type=button,对于默认按钮,请使用type=submit(下面提供了示例:https://dev59.com/C3I-5IYBdhLWcg3wN1lD#24245422)。 - dmitry_romanov
@GrahamKlyne - display:none 在今天的浏览器中表现不一致。请参考 http://codepen.io/shanplourde/pen/pJYrJV 的例子。 - Shan Plourde
2
@dmitry_romanov和他的评论点赞者:不,type=button不会提交表单,因此根据@spikyjt的评论(在上面某个地方),无法解决OP的问题。 - Sz.
@Sz。它的意思是“将type=submit设置为您想要成为默认按钮的按钮...”;其他按钮的作用由UI创建者决定。问题在于不是第一个按钮成为默认按钮,而是另一个按钮,这个问题通过技巧得到解决。我也遇到了同样的问题,这个解决方案对我非常有效 :-) - dmitry_romanov
显示剩余2条评论

81

我的建议是不要抵触这种行为。你可以使用浮动元素有效地改变它们的顺序。例如:

<p id="buttons">
<input type="submit" name="next" value="Next">
<input type="submit" name="prev" value="Previous">
</p>

使用:

#buttons { overflow: hidden; }
#buttons input { float: right; }

将有效地颠倒顺序,因此按回车键触发的值将是“下一个”按钮的值。

这种技术可以涵盖许多情况,而无需采用更具hack性质的JavaScript方法。


还有其他可能的“CSS”定位技巧吗? - Salman A
2
我成功地将下一个按钮向右推,方法是:(1)将其向右浮动,(2)将所有其他按钮向左浮动,(3)将所有按钮显示为块,(4)在源顺序中指定所有按钮,包括下一个按钮。 - Salman A
1
非常好,谢谢!我只想补充一下,如果你想让按钮组仍然向左浮动,只需要在“buttons”ID元素中添加一个向左浮动的div,然后你的按钮将按照所需的顺序重新排序,但是按钮组将保持向左浮动。 - Scott Gardner
谢谢,这个解决方案非常棒!!!我之前在想一些不好看的 JavaScript hack。 - Bhavesh G
2
这个解决方案的主要问题是它会破坏选项卡索引。使用CSS重新定位按钮并不会改变它们的选项卡索引顺序。因此,按下Tab键时,焦点不会始终从上/下、左到右移动。请参见https://dev59.com/C3I-5IYBdhLWcg3wN1lD#31911751,以获取解决此问题的解决方案。 - Shan Plourde

38

设置为您想要成为默认按钮的按钮,将设置为其他按钮。现在,在下面的表单中,您可以在任何输入字段中按Enter键,按钮将起作用(尽管它是表单中的第二个按钮)。

示例:

    <button id='close_button' class='btn btn-success'
            type=button>
      <span class='glyphicon glyphicon-edit'> </span> Edit program
    </button>
    <button id='render_button' class='btn btn-primary'
            type=submit>             <!--  Here we use SUBMIT, not BUTTON -->
      <span class='glyphicon glyphicon-send'> </span> Render
    </button>

已在FF24和Chrome 35中测试。


28
除了 type="button" 不会提交表单之外,其他按钮仍然需要提交表单但不是默认的。需要使用额外的 JavaScript 使它们提交表单,这意味着最好使用 CSS 重新定位它们。 - spikyjt

37

您可以快速简单地创建一个隐藏的提交按钮副本,当按下回车键时应使用该按钮。

CSS示例

input.hidden {
    width: 0px;
    height: 0px;
    margin: 0px;
    padding: 0px;
    outline: none;
    border: 0px;
}

示例HTML

<input type="submit" name="next" value="Next" class="hidden" />
<input type="submit" name="prev" value="Previous" />
<input type="submit" name="next" value="Next" />

如果有人在您的表单中按下回车键,那么(隐藏的)下一个按钮将被用作提交者。

已在IE9、Firefox、Chrome和Opera上进行测试


3
我唯一的建议是确保解决可访问性问题和tabindex问题。由于按钮在技术上并未隐藏,只是在实际上隐藏了,所以屏幕阅读器和辅助设备仍会识别该按钮。此外,目前的按钮仍然是可通过 tab 键聚焦的。将 tabindex 设置为“-1”即可修正这个问题。 - Shan Plourde
2
为了隐藏按钮,使其在辅助工具(屏幕阅读器)中不可见,请将role=none添加到其属性中。 - Radek Pech
1
一个简单的"display: none;"似乎也可以起作用?这还解决了屏幕阅读器的问题。 - Steven Jeuris
我测试过的所有浏览器/浏览器版本都不能正常使用"display: none"。 - scotty86
除上述之外,使用 display: none 在 Firefox 和 Chrome 中有效,但在 Safari 中无效。为了获得最佳的跨浏览器支持,我使用了以下 CSS:height: 0; visibility: hidden; 并添加了以下属性:aria-hidden="true" tabindex="-1" - Tom Spencer
@TomSpencer: 别忘了 width: 0。但是 display: none 应该被 Safari 支持:https://developer.mozilla.org/de/docs/Web/CSS/display - scotty86

28

如果您正在使用jQuery,这个源自这里的评论提供了一个相当简洁的解决方案:

$(function(){
    $('form').each(function () {
        var thisform = $(this);
        thisform.prepend(thisform.find('button.default').clone().css({
            position: 'absolute',
            left: '-999px',
            top: '-999px',
            height: 0,
            width: 0
        }));
    });
});

只需在您想要设置为默认的按钮上添加class="default"即可。它会在表单开头放置一个隐藏的该按钮副本。


5

我重新发布这个帖子是因为我在研究一种非JavaScript的方法来实现这个。我不想使用键盘处理程序,并且CSS定位会导致选项卡顺序中断,因为CSS重新定位不会改变选项卡顺序。

我的解决方案基于https://dev59.com/F3NA5IYBdhLWcg3whuZ_#9491141的回答。

以下是解决方案源代码。tabindex用于修正隐藏按钮的选项卡行为,而aria-hidden则避免了屏幕阅读器朗读该按钮/辅助设备识别该按钮。

<form method="post" action="">
  <button type="submit" name="useraction" value="2nd" class="default-button-handler" aria-hidden="true" tabindex="-1"></button>
  <div class="form-group">
    <label for="test-input">Focus into this input: </label>
    <input type="text" id="test-input" class="form-control" name="test-input" placeholder="Focus in here and press enter / go" />
  </div>

DOM中的第一个按钮 DOM中的第二个按钮 DOM中的第三个按钮

此解决方案所需的基本CSS:

.default-button-handler {
  width: 0;
  height: 0;
  padding: 0;
  border: 0;
  margin: 0;
}

1
虽然这理论上回答了问题,但最好在此处包含答案的基本部分,并提供参考链接。 - Vladimir Panteleev

1
另一种解决方案,使用jQuery:

$(document).ready(function() {
  $("input").keypress(function(e) {
    if (e.which == 13) {
      $('#submit').click();
      return false;
    }

    return true;
  });
});

这应该适用于以下表单,使“更新”成为默认操作:
<form name="f" method="post" action="/action">
  <input type="text" name="text1" />
  <input type="submit" name="button2" value="Delete" />
  <input type="submit" name="button1" id="submit" value="Update" />
</form>

以及:

<form name="f" method="post" action="/action">
  <input type="text" name="text1" />
  <button type="submit" name="button2">Delete</button>
  <button type="submit" name="button1" id="submit">Update</button>
</form>

这将仅在表单中的输入字段具有焦点时捕获Enter键。

0

您不应该使用相同名称的按钮,这会导致语义不清。相反,您应该修改后端代码以查找设置不同名称值的按钮:

<input type="submit" name="COMMAND_PREV" value="&lsaquo; Prev">
<input type="submit" name="COMMAND_SAVE" value="Save">
<input type="reset"  name="NOTHING" value="Reset">
<input type="submit" name="COMMAND_NEXT" value="Next &rsaquo;">
<input type="button" name="NOTHING" value="Skip &rsaquo;" onclick="window.location = 'yada-yada.asp';">

由于我不知道您在后端使用的是哪种语言,因此我将为您提供一些伪代码:

if (input name COMMAND_PREV is set) {

} else if (input name COMMAND_SAVE is set) {

} else if (input name COMMENT_NEXT is set) {

}

4
仅仅依靠按钮的“值”来确定哪个被点击是非常脆弱的。任何微小的UI更改或本地化工作都需要更改后端以进行检测。而且,如果其中有非ASCII字符,您必须确保编码在所有地方都设置正确! - bobince
2
嗯...我可以接受这个,但这仍然意味着“Prev”充当了“默认”按钮。 - Salman A
1
@Salman,你应该结合@cletus的CSS定位建议使用我的建议,以确保你正确地首先声明默认按钮。 - Corey Ballou
3
这是一个有道理的观点,但它并没有回答问题。 - DanMan

-1

bobince的解决方案的缺点是创建了一个可以通过Tab键跳过,但其他情况下无法使用的按钮。这可能会给键盘用户带来困惑。

另一种解决方案是使用鲜为人知的form属性:

<form>
    <input name="data" value="Form data here">
    <input type="submit" name="do-secondary-action" form="form2" value="Do secondary action">
    <input type="submit" name="submit" value="Submit">
</form>

<form id="form2"></form>

这是标准的HTML,但不幸的是在Internet Explorer中不支持。


规范似乎没有表明设置表单所有者会导致该按钮充当默认按钮,您确认了吗?owner属性似乎存在以解决嵌套HTML表单的问题。此外,如果多个按钮分配了相同的表单属性,会发生什么? - Shan Plourde
如果我没记错的话,规范指出默认按钮是表单拥有的DOM顺序中的第一个按钮。多个按钮仍符合该规则 - 就提交表单而言,它们的行为就像它们是表单的一部分一样(因此第一个按钮是默认的)。 - Vladimir Panteleev
没错,但表单所有者被暗示为当前表单。如果您不指定表单属性,则默认为按钮/输入的第一个父表单作为所有者。在单个表单场景中,您的建议无法实现,因为每个提交按钮都假定具有相同的表单所有者。例如,您将无法使回车键提交该表单上的三个按钮中的第二个。 - Shan Plourde
当然,它会提交所属表单。我认为这很明显。对于“删除”或“取消”等操作没有问题,您可以使用隐藏输入来识别该项。 - Vladimir Panteleev
因为这个回答没有完成Salmon A的要求,我会给它点个踩。如果你能验证你的回答,我会取消这个踩。 - Shan Plourde
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接