打印

HF5011: 多个 target 属性设置的目标窗口不为当前窗口的 FORM 同时提交后 Chrome Safari 中仅打开一新个窗口

作者:钱宝坤

标准参考

表单是 HTML 文档的一部分,它包含文档内容、标记和特殊的元素控件 (checkboxes、radio、buttons、menus 等)。它包含 action、method、target、enctype、accept-charset、accept 等属性。FORM 元素扮演着控件容器的角色,它指定了如下规则:

  • 其内元素的布局;
  • 由 action 属性值 (例如,这个值可以是 HTTP URI 或 mailto URI) 所指定的程序将要处理已经填写完毕并且已经提交的 FORM,这个接收程序必须能够从语法上描述或分析这个 FORM 的属性名称及与之对应的属性值 (name/value pairs) 以便可以利用它们;
  • 要指定用户数据集将要通过什么方法 (get 或 post) 发送到服务器端;
  • 所采用的字符编码方式 (由 accept-charset 属性指定) 必须是能够被服务器端接受的以便处理被提交的 FORM 中的数据集。

FORM 的 target 属性指定该表单的处理结果在哪里显示,target 的值为窗口名。可称之为“目标窗口”。

关于 FORM 元素的更多内容,请参考 HTML4.01 17.1 Introduction to forms 中的内容。

关于 target 属性值类型 的更多内容,请参考 HTML4.01 6.16 Frame target names 中的内容。

问题描述

当页面中存在多个 FORM 元素,它们的 target 属性设置的目标窗口均不为当前页面 URI 时,若同时提交这些 FORM,Chrome Safari 中只能自动打开一个窗口,而其他浏览器会同时打开多个窗口。

造成的影响

此问题将造成多个 FORM 同时被提交到新窗口时,仅有一个 FORM 提交后的结果在 Chrome Safari 中可见。

受影响的浏览器

Chrome Safri  

问题分析

FORM 的 target 属性能够指定该表单的处理结果显示的目标窗口,当目标窗口不存在时,浏览器会新开一个名称为该值的窗口。

一般情况,有两种 target 属性设置可以促使浏览器打开新窗口。

一种是 FORM 的 target 属性的值为某具体窗口名,如果该名窗口在浏览器窗口列表中不存在时,浏览器会打开一个新窗口,并将 target 属性的值设置为该窗口名。然后在该窗口中显示 FORM 的处理结果。

另一种是 FORM 的 target 属性值设置为 _blank,他会将表单内容提交到新打开的窗口中。

 

但当使用脚本同时提交多个 FORM 时,在 Chrome Safari 中的表现却与其他浏览器不同,如以下代码:

<body>
<form method="get" action="recieve.html" target="f_1">
  <input type="text" name="key" value="form1">
  <input type="submit" />
</form>
<form method="get" action="receive.html" target="f_2">
  <input type="text" name="key" value="form2">
  <input type="submit" />
</form>
<form method="get" action="receive.html" target="f_3">
  <input type="text" name="key" value="form3">
  <input type="submit" />
</form>
<form method="get" action="receive.html" target="_blank">
  <input type="text" name="key" value="form4">
  <input type="submit" />
</form>
<form method="get" action="receive.html" target="_blank">
  <input type="text" name="key" value="form5">
  <input type="submit" />
</form>
<form method="get" action="receive.html" target="_blank">
  <input type="text" name="key" value="form6">
  <input type="submit" />
</form>
<input id="submit" type="button" value="同时提交表单">
<script>
  window.onload = function(){
    document.getElementById('submit').onclick=function(){
      for(var i = 0, forms = document.forms; forms[i]; forms[i++].submit());
    };
  }
</script>
</body>

数据接收页面(receive.html)测试代码如下:

<body>
<div id="key"></div>
<script type="text/javascript">
  var $key=document.getElementById("key");
  $key.innerHTML=location.search.substring(1);
</script>
</body>

第一部分代码通过脚本同时提交了六个 FORM ,前三个对应的各自名称固定的窗口(如果这些窗口不存在则会新开窗口),后三个每个都会提交到新窗口中。

第二部分代码可以显示 FORM 提交的参数。

运行以上代码,使用同时提交方法,在各浏览器中运行的情况如下:

同时提交 IE6 IE7 IE8 1 Firefox Opera Chrome Safari
打开窗口情况 同时打开多个窗口 一次只创建一个新窗口 2
表单数据接收情况

窗口 "f_1" :key=form1

窗口 "f_2" :key=form2

窗口 "f_2" :key=form3

无名新窗口 :key=form4

无名新窗口 :key=form5

无名新窗口 :key=form6

窗口 "f_1" :key=form1

依次点击各个表单的单独提交按键:

手工依次提交 IE6 IE7 IE8 1 Firefox OperaChrome Safari
打开窗口情况 可以打开多个窗口
表单数据接收情况

窗口 "f_1" :key=form1

窗口 "f_2" :key=form2

窗口 "f_2" :key=form3

无名新窗口 :key=form4

'overflow' 特性值不为 'visible'

无名新窗口 :key=form5

无名新窗口 :key=form6

注 1: 在 IE9 Beta 版中此问题的表现与 IE 其他版本一致。
注 2: Chrome Safari 一次只可以同时创建一个新窗口,这个新窗口是由第一个表单创建的,其后的新窗口都没有被一次创建出来。如果保持打开的窗口不关闭,多次点击同时提交按钮,则每次点击都可以依照表单提交顺序依次将全部窗口创建出来。这种情况可能有读者会怀疑是否为同时提交多个表单会受到这两个浏览器的拦截,如果修改代码使用 setTimeout 延时依次提交表单是否可以避免这个情况?事实证明即使延时提交也是如此情况,因此并非同时提交和延时提交到导致的问题,只有用户手工提交才可以正常创建新窗口。

根据上表情况可知,Chrome Safari 中无法通过脚本程序同时提交多个表单,但是通过用户手动提交则可以成功。这很有可能是 WebKit 浏览器引擎的防范恶意脚本功能一部分,用来防止恶意代码一次性提交多个表单。

解决方案

这个问题是 WebKit 核心浏览器的特性,如果需要同时提交多个表单,请将 target 的值分别设置具体窗口名,并使用 window.open 方法主动打开目标窗口,不要不依赖浏览器自动行为。

如,可以将上例代码一中 "target=_blank" 修改为具体窗口名,并将脚本修改为:

document.getElementById("submit").onclick = function () {
  for (var i = 0, forms = document.forms; forms[i]; window.open('about:blank', forms[i].target), document.forms[i++].submit());
};

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6.10
Chrome 7.0.517.8 dev
Safari 5.0.2
Opera 10.62
测试页面: forms.html
本文更新时间: 2010-10-27

关键字

FORM target submit 提交