使用JavaScript区分表单中的两个提交按钮

6
我该如何在javascript中找出哪个提交按钮被点击了?
function submitForm(){
   //if find open popup
   //else if add continue in the same window

}

<form action="/findNames" onsubmit="return submitForm()">
    <input type="submit" value="Add" onclick="submitForm(this)"/>
    <input type="submit" value="Find" onclick="submitForm(this)"/>
</form>

我尝试的方法:

我尝试使用onclick来实现,但是当“查找”按钮被点击时,它会打开一个弹出窗口并提交父窗口。我该如何阻止它提交父窗口?

function submitForm(submit){
    if(submit.value=="Find"){
        find();//opens a popup window
    }else if(submit.value == "Add"){
        //stay in the same window
    } 
}

function find(){
    var width  = 1010;
    var height = 400;           
    var params = 'width='+width+', height='+height;     
    popupWin = window.open('find.do','windowname5', params);
    popupWin.focus();
}

<form action="/findNames">
    <input type="submit" value="Add" onclick="submitForm(this)"/>
    <input type="submit" value="Find" onclick="submitForm(this)"/>
</form>

不确定,但你尝试给“input”标签添加“name”属性了吗? - piokuc
1
为什么不将它分成两个表单? - Marcos
@piokuc 我试过了,但是如何在JavaScript中访问name属性值呢? - Susie
3
你应该考虑使用事件监听器来捕获你的点击事件,而不是将函数调用与 HTML 代码绑定在一起(这已经被弃用了)。 - Malkus
您可以通过DOM访问表单、输入标签及其属性。我刚刚在谷歌上搜索了“如何在JavaScript中访问name属性值”,出现了一些讨论此问题的页面。 - piokuc
@MikeB,事实恰恰相反。事件处理程序属性符合标准并且始终有效;事件侦听器不总是有效(API取决于DOM实现)。HTML5甚至引入了新的事件处理程序属性,那么它们怎么可能被弃用呢?不要跳上“非侵入式JavaScript”列车,它由一些自命不凡的人运营。 - PointedEars
4个回答

7

type="submit"input 总是会提交表单。使用 type="button"input 创建一个不提交的按钮。


我最初把其中一个设为按钮。这个表单有很多输入字段,我的问题是当我点击按钮时,我需要将这些输入字段中的值提交到服务器。 - Susie
根据W3Schools的说明,只有带有name属性的input标签才会将其值提交到服务器。 - Kninnug
1
@Kninnug W3Schools是垃圾网站,但在这种情况下是正确的。然而,“表单控件的值”没有被提交并不意味着“表单”没有被提交。换言之,表单仍然被提交。 - PointedEars
当您点击一个按钮而不是“提交”按钮时,输入值不会被提交。我该如何使其提交表单中的所有输入,即使您点击了这个“按钮”? - Susie
@PointedEars 说得好,但 Susie,你现在究竟想要什么?在添加和查找情况下,表单必须同时提交吗? - Kninnug
显示剩余2条评论

4

您已经走在正确的道路上,但是因为没有取消事件(或者按照 DOM Level 2+ 的说法,您没有“阻止事件的默认行为”),所以您的表单总是提交。

function submitForm (button)
{
  if (button.value == "Find")
  {
    /* open popup */
    find();
  }
  else if (button.value == "Add")
  {
    /* stay in the same window */
  } 

  return false;
}

<form action="/findNames">
  <input type="submit" value="Add" onclick="return submitForm(this)"/>
  <input type="submit" value="Find" onclick="return submitForm(this)"/>
</form>

永远不要将表单相关的变量命名为submit,因为如果您不小心这会覆盖form对象的submit方法。

当返回值false传递给事件处理程序时,它会阻止click事件的默认操作。这意味着用户代理工作就像提交按钮从未被激活一样,表单不会被提交。

解决这个问题的另一种方法是将标识点击的提交按钮的值保存在变量或属性中,并在submit事件侦听器中检查该值。这是因为input(提交按钮)的click事件定义在formsubmit事件之前:

var submitName;

function submitForm (form)
{
  if (submitName == "Find")
  {
    /* open popup */
    find();
  }
  else if (submitName == "Add")
  {
    /* stay in the same window */
  } 

  return false;
}

function setSubmit (button)
{
  submitName = button.value;
}

<form action="/findNames" onsubmit="return submitForm(this)">
  <input type="submit" value="Add" onclick="setSubmit(this)"/>
  <input type="submit" value="Find" onclick="setSubmit(this)"/>
</form>

(这只是一个例子。尽量减少全局变量的数量。)

再次强调,当返回值false被返回到submit事件处理程序时,会阻止表单提交。如果您明确希望在处理了submit事件后提交表单,则可以返回true。例如,您可能希望验证表单,如果验证成功,则通过target属性在另一个框架中显示服务器响应。

与在脚本代码中添加事件监听器相比,事件处理程序属性的优点是运行时效率高、向后兼容且仍符合标准。缺点是如果事件不冒泡,您可能需要复制事件处理程序代码。(这里没有问题。)

其他人可能会说事件处理程序属性的缺点也在于标记和函数之间没有分离;然而,您应该自己做出判断。在我看来,函数总是与特定的标记相关联,为了解决不同的DOM实现而跳跃是很少值得的。

另请参见:DOM客户端对象交叉引用:DOM事件

这里最重要的是,无论您进行了多少客户端改进,表单都保持可访问性,即使没有客户端脚本,它仍然可以使用键盘工作。您的服务器端脚本(这里是:/findNames)可以作为后备,客户端脚本可以避免不必要的往返传输,提高用户体验并减少网络和服务器负载。


3

您的代码应该重构以正确附加事件监听器。

首先,定义将作为侦听器的函数:

function preventSubmission(e) {
    if (e.preventDefault) e.preventDefault();
    return false;
}

function find(){
    var width  = 1010;
    var height = 400;           
    var params = 'width='+width+', height='+height;     
    popupWin = window.open('find.do','windowname5', params);
    popupWin.focus();
}

然后,缓存与相关表单元素的引用:
var form = document.getElementById('my-form'),
    findButton = document.getElementById('find');

最后,将监听器添加到DOM事件中:
if (form.addEventListener) {
    form.addEventListener("submit", preventSubmission);
    findButton.addEventListener("click", find);
} else {
    form.attachEvent("submit", preventSubmission);
    findButton.attachEvent("click", find);
}

这是一个完整的演示例子: http://jsfiddle.net/CQAHv/2/

1
错误:−1。不需要显式事件侦听器(它们隐含在事件处理程序属性中),而attachEventaddEventListener不等效 - PointedEars
3
是的,但内联HTML事件处理程序被认为是不好的做法。 - chrx
此外,我知道attachEvent和addEventListener不是同一种东西:因此需要有条件语句。IE8及以下版本需要使用attachEvent。 - chrx
不,它们并非“被视为不良实践”;你听错了人。而且你还没有意识到其中的差异。IE8及以下版本不需要使用attachEvent,它们可以像其他DOM 0浏览器一样工作(例如Netscape 3.0)。除非有MSHTML-特定原因使用它,否则应避免使用attachEvent - PointedEars
1
在 IE 9 之前的 Internet Explorer 版本中,您必须使用 attachEvent 而不是标准的 addEventListener。 - chrx
显示剩余4条评论

2
请看这个:
Javascript:
(该文本段落为英语,无法翻译。)
var clicked;
var buttons = document.getElementsByTagName("input");

for(var i = 0; i < buttons.length;i++)
{
    var elem = buttons[i];
    if(elem.type=="submit")
    {
        elem.addEventListener("click", function(){ clicked=this.value;}, false);
    }
}


window.onsubmit = function(e)
{
   alert(clicked);
    return false;
}

标记语言:
<form action="/findNames">
    <input type="submit" value="Add" />
    <input type="submit" value="Find" />
</form>

您将获得任何按钮被点击的值。
jsFiddle:http://jsfiddle.net/hescano/v9Sz2/ 注意:为了测试目的,我在onsubmit事件中有一个return false。第一个jsFiddle示例包含了它自己的window.onload,因此您可能需要将不在window.onsubmit内部的所有内容都添加到window.onload中,例如这样http://jsfiddle.net/hescano/v9Sz2/1/(已在Chrome、Firefox中测试)。

将属性添加到 window 已经够糟糕了,但是真的要用 window.onsubmit 吗?submit 事件并不会在所有地方冒泡。 - PointedEars
你的意思是它不会在任何地方冒泡吗?这个解决方案适用于多个浏览器,并且window.onsubmit在这种情况下完全有效。 - Hanlet Escaño

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