如果在表单提交之前尝试重定向会发生什么?

6

我在处理的一个网站中发现了这段奇怪的代码,但是我不明白为什么会出现我看到的行为。

<input type="submit" value="Save" onclick="document.location.href='http://www.google.com'" />

(已更改 href,它实际上指向与表单的 action 相同的 URL)。

由于 onclick 事件在提交表单之前触发,所以我期望这段代码将页面重定向到 Google.com,从而停止执行页面并永远不会提交表单。或者可能重定向到 Google.com,但仍然完成提交表单。

但实际上发生的是重定向被完全忽略了,表单仍然被提交。为什么会发生这种情况呢?
我确认 onclick 事件确实能够触发;我将重定向移到一个函数中,并在 onclick 中调用该函数。这个函数在提交之前被正常调用,但重定向似乎被忽略了。


我知道返回 false 会阻止提交,在这种情况下重定向确实会发生。但为什么在这种情况下重定向不会发生?是什么阻止了它? - GendoIkari
你能在jsfiddle上重新制作一下吗?并告诉我们你正在测试哪个浏览器? - Mario S
我最近也遇到了同样的问题。你可以使用<button>...</button>,并在按钮的动作事件代码末尾附加someform.submit()。或者,你可以覆盖onsubmit表单属性或相应的提交事件处理程序。 - Lorenz Lo Sauer
4个回答

5

我刚刚在不同的浏览器中测试了这种行为,所有浏览器都给出了相同的结果,这是我的结论:

<!-- submit button inside form -->
<form method="post">
    <input type="submit" value="submit" /> <!-- onclick = submitted to same page -->
    <input type="submit" value="submitNredirect" onclick="document.location.href='http://www.google.com';" /> <!-- onclick = submitted to same page, ignored redirect -->
</form>
<!-- submit button without form -->
<input type="submit" value="submit" /> <!-- onclick = no submit or redirect occur -->
<input type="submit" value="submitNredirect" onclick="document.location.href='http://www.google.com';" /> <!-- onclick = redirect -->

如您所知,Javascript 是一种线性语言,它按照代码行的顺序执行。我们假设有以下表单:

<form id="myform" method="post" onsubmit="alert('onsubmit');">
    <input id="mybtn" type="submit" value="submit" onclick="alert('onclick');" />
</form>
<script>
    $(document).ready(function() {
        $('#mybtn').bind('click', function() {
            alert('bind click');
        });
        $('#myform').bind('submit', function() {
            alert('bind submit');
        });
        // onclick > bind click > onsubmit > bind submit
    });
</script>

点击按钮时,首先触发绑定到该按钮的事件("click" 事件),然后触发绑定到表单上的事件("submit" 事件)。结果如下:
  1. alert: onclick
  2. alert: bind click
  3. alert: onsubmit
  4. alert: bind submit
  5. 表单提交
如果在任何函数中包含重定向代码,则重定向将被忽略并进行提交。我相信 JavaScript 会使用表单提交过程覆盖 `document.location.href`,"表单提交" 就像脚本末尾的隐式/隐藏代码一样。如果你在某个点上没有使用 `return false;`,则会执行此隐式/隐藏行。
我不是专家,但这就是我经过一些测试后了解到的内容。如果我有所错误,请纠正我。
编辑:如果我们在每个函数中都包含一个 `document.location.href`,会发生什么?就像这样:
<form id="myform" method="post" onsubmit="document.location.href='http://www.onsumbit.com';">
    <input id="mybtn" type="submit" value="submit" onclick="document.location.href='http://www.onclick.com';" />
</form>
<script>
    $(document).ready(function() {
        $('#mybtn').bind('click', function() {
            document.location.href='http://www.bindclick.com';
            return false;
        });
        $('#myform').bind('submit', function() {
            document.location.href='http://www.bindsumbit.com';
        });
    });
</script>

"href"字符串值的状态如下所示(但在脚本结束时执行重定向):
  1. document.location.href = 'http://www.onclick.com';
  2. document.location.href = 'http://www.bindclick.com';
  3. document.location.href = 'http://www.onsubmit.com';
  4. document.location.href = 'http://www.bindsubmit.com';
  5. document.location.href = '/'; // 表单提交
  6. JavaScript,根据“href”字符串值进行重定向
但是我们在 #2 后加了 return false;,这意味着将对 "http://www.bindclick.com" 进行重定向。

@LoSauer 我知道,我只是在使用jQuery进行测试,因为问题不是关于代码,而是关于JavaScript的行为方式。 - evilReiko
我明白。但这与JavaScript或其“线性”几乎没有关系。它涉及处理程序以及因此在特定浏览器实现中设置input[type=submit]的事件冒泡方式。一个选项是覆盖这些处理程序... - Lorenz Lo Sauer
@LoSauer 如果提交是唯一的问题,请参考此链接http://www.echoecho.com/htmlforms12.htm,这里有更详细的解释。input[type=submit]是将事件绑定到任何类型为submit的输入标签的jQuery/JavaScript代码。即使忽略这些步骤,行为序列在删除jQuery后仍将保持不变。希望这能让事情更清楚 :) - MarmiK
@MarmiK,@evilReiko。这篇文章有几个缺陷:*)使用包装库来研究特定的浏览器行为是有缺陷的。*)设置document.location.href来说明一点是严重有缺陷的,除非你设置锚点。*)没有回答为什么,只列出了事件层次结构。 - Lorenz Lo Sauer
如果我理解正确的话,实际上这很清楚地回答了“为什么”的问题。因为设置document.location.href并不会立即重定向;相反,它会导致Javascript在处理完页面后才进行重定向。事实上,我刚刚通过在重定向前后放置一个警报来测试了一下。我得到了两个警报,然后它重定向了。这似乎证实了答案所说的。谢谢! - GendoIkari

0

我认为这是一个有争议的问题,

我将从行为方面回答,

表单的默认方法是GET,因此在提交按钮按下时,表单将获取数据。来源旧帖子

但是,如果您在e.preventDefault()中包含document.location.href="http://www.google.com",

现在,如果链接是index.html,则将根据网站地址调用本地索引页面,因为您已删除原始链接,所以不可能判断最初为什么使用它们!!!???

我可以说,在您的问题中运行此代码,

<form onsubmit="javascript:alert('Form Submit called '+ this.method);">
    <input type=submit value=Submit onclick="javascript:document.location.href='http://www.google.com';alert('Button Submit');" />
</form>

这将清除流程的调用。因为使用此方法不会更改document.location.href。

在更改href后使用此代码alert(document.location.href);,这将给出未更改的位置。

也许防止默认行为可能会改变这一点,但这不是您的代码的一部分。

我希望这能让事情更清楚。


0
你所观察到的是 HTMLInputElement 的默认和继承处理程序的行为,除非被覆盖。
解决方案:
使用HTML5 button type-submit Element代替,这应该能够被所有现代浏览器正确处理。
<form action="/" method="post" onsubmit="alert('submit event')">
  <input type="text" name="someinput" value="100">
  <button type="submit" onclick="alert('button onclick handled before form-submit')">submit</button>
</form>

解释:

您没有提供具体的浏览器,但也许您正在使用WebKit,它在onsubmit / onclick事件层次结构before中存在问题。

在项目的代码网站上,您可以搜索实现各种HTMLElement的代码。
例如,搜索onsubmit将导致Webkit onsubmit-event bubbling test

解决此事件冒泡问题的一种方法是使用一个button并将其呈现为“submit”,通过查找其封闭表单并通过函数(HTMLFormElement-instance).submit()提交它。

另一种方法是通过更改表单的提交处理程序来实现,这应该是您要寻找的。

<form action="/" method="post" accept-charset="utf-8" id="myform3"
   onsubmit="event.stopPropagation(); event.cancelBubble = true;">
   A form with the default Browser submit-handler overwritten:
   <br>
   <input type="text" name="someinput" value="100">
   <input type="submit" name="commit" value="Submit" 
     onclick="alert('will alert first and submit later  using the browser default submit handler.');">
 </form>

所有案例都在这个fiddle中演示。

干杯!


0
<form action="http://www.yahoo.com" method="get">
<input type="submit" value="Save" onclick="document.location.href='http://www.google.com'" />
</form>

点击保存按钮后,我发现根据不同的浏览器,你可能会被重定向到雅虎(Chrome),除非你将返回false添加到onclick事件中。在IE 10上,你会被重定向到谷歌。
我认为编写浏览器的人需要回答这个问题。

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