无
Chrome Safari 子页面中使用 frames 集合获取其父页面中通过 innerHTML 移动位置后的 IFRAME 元素得到的对象类型为 HTMLIFrameElement,而不是正常的
Window,这将导致其下的 document 等子对象无法访问。
Firefox 中,子页面中获取在 window.onload 中移动位置后的 IFRAME 元素 window 对象内的一些子对象可能出错。
触发此问题后会影响 IFRAME 内外页面的交互,可能造成各种兼容性问题。
Chrome Safari Firefox |
---|
window 对象中的 frames 集合可以返回当前 window 中的子框架列表,这是一个类似数组的集合对象。可以通过整型下标或者子框架元素的 name 属性获取到该集合内对应的子框架 window 对象。
IFRAME 元素对应的 DOM 对象为 HTMLIframeElement,各浏览器均支持 HTMLIframeElement 接口中的 contentWindow 属性,这个属性返回 IFRAME 引入子页面的 window 对象。
假设在当前父页面中存在一个 id 和 name 属性为 "ifr" 的 IFRAME 对象,则可以通过 window.frames["ifr"] 或者 document.getElementById("ifr").contentWindow 这两组方法获取到 IFRAME 引入页面的 window 对象。这两种方法在所有主流浏览器中均有很好的兼容性。但是却并不符合 W3C 规范。其中 window.frames 集合算 DOM Level 0 范畴,而 contentWindow 属性为 IE5.5 引入。
关于 window.frames 集合的相信资料,请参考:MSDN、Mozilla Developer Center、Safari Refernece Library。
关于 contentWindow 属性的详细资料,请参考:MSDN、Mozilla Developer Center、Safari Refernece Library。
下面分 4 种情况测试当 IFRAME 元素在文档树中发生变化对 IFRAME 内外的子页面与父页面交互的影响。
测试代码如下:
main1.html
<style> iframe { width:450px; height:1800px; } </style> before window.onload, innerHTML <div id="div1"> <iframe id="ifr1" name="ifr1" src="sub.html"></iframe> <iframe id="ifr2" name="ifr2" src="0.html"></iframe> </div> <div id="div2"> </div> <script> function $(id) { return document.getElementById(id); } $("div2").innerHTML = $("div1").innerHTML; $("div1").innerHTML = ""; </script> |
main2.html
<style> iframe { width:450px; height:1800px; } </style> before window.onload, appendChild <div id="div1"> <iframe id="ifr1" name="ifr1" src="sub.html"></iframe> <iframe id="ifr2" name="ifr2" src="0.html"></iframe> </div> <div id="div2"> </div> <script> function $(id) { return document.getElementById(id); } var iframe1 = $("div1").children[0]; var iframe2 = $("div1").children[1]; $("div1").removeChild(iframe1); $("div1").removeChild(iframe2); $("div2").appendChild(iframe1); $("div2").appendChild(iframe2); </script> |
main3.html
<style> iframe { width:450px; height:1800px; } </style> after window.onload, innerHTML <div id="div1"> <iframe id="ifr1" name="ifr1" src="sub.html"></iframe> <iframe id="ifr2" name="ifr2" src="0.html"></iframe> </div> <div id="div2"> </div> <script> function $(id) { return document.getElementById(id); } window.onload = function () { $("div2").innerHTML = $("div1").innerHTML; $("div1").innerHTML = ""; } </script> |
main4.html
<style> iframe { width:450px; height:1800px; } </style> after window.onload, appendChild <div id="div1"> <iframe id="ifr1" name="ifr1" src="sub.html"></iframe> <iframe id="ifr2" name="ifr2" src="0.html"></iframe> </div> <div id="div2"> </div> <script> function $(id) { return document.getElementById(id); } window.onload = function () { var iframe1 = $("div1").children[0]; var iframe2 = $("div1").children[1]; $("div1").removeChild(iframe1); $("div1").removeChild(iframe2); $("div2").appendChild(iframe1); $("div2").appendChild(iframe2); } </script> |
sub.html
<html> <head> <style> * { font:12px Arial; } body { margin:0; } span { font-weight:bold; } .g { color:green; } .r { color:red; } </style> </head> <body> <dl> <script> function myEval (code) { var script = document.createElement("script"); script.text = "var ret =" + code; document.body.appendChild(script); var x = ret; document.body.removeChild(script); return x; } function tryObj (obj_text) { var ok = '<span class="g">OK</span>'; var fail = '<span class="r">FAIL</span>' try { var f = ""; var ev = myEval(obj_text); try { f = ev.toString(); } catch(e) { f = ""; } return ev ? ok + " " + f : fail + " " + f; } catch(e) { return fail + " " + f; } } var arr = [ 'parent', 'parent.document', 'parent.document.getElementById("ifr1")', 'parent.document.getElementById("ifr1").contentWindow', 'parent.document.getElementById("ifr1").contentWindow.document', 'parent.document.getElementById("ifr1").contentWindow.history', 'parent.document.getElementById("ifr1").contentWindow.location', 'parent.document.getElementById("ifr1").contentWindow.navigator', 'parent.document.getElementById("ifr1").contentWindow.screen', 'parent.document.getElementById("ifr1").contentWindow.alert', 'parent.document.getElementById("ifr2")', 'parent.document.getElementById("ifr2").contentWindow', 'parent.document.getElementById("ifr2").contentWindow.document', 'parent.document.getElementById("ifr2").contentWindow.history', 'parent.document.getElementById("ifr2").contentWindow.location', 'parent.document.getElementById("ifr2").contentWindow.navigator', 'parent.document.getElementById("ifr2").contentWindow.screen', 'parent.document.getElementById("ifr2").contentWindow.alert', 'parent.frames', 'parent.frames["ifr1"]', 'parent.frames["ifr1"].document', 'parent.frames["ifr1"].history', 'parent.frames["ifr1"].location', 'parent.frames["ifr1"].navigator', 'parent.frames["ifr1"].screen', 'parent.frames["ifr1"].alert', 'parent.frames["ifr2"]', 'parent.frames["ifr2"].document', 'parent.frames["ifr2"].history', 'parent.frames["ifr2"].location', 'parent.frames["ifr2"].navigator', 'parent.frames["ifr2"].screen', 'parent.frames["ifr2"].alert' ]; for (var i in arr) { document.write('<dt>' + arr[i] + ':</dt>'); document.write('<dd>' + tryObj(arr[i]) + '</dd>'); } </script> </dl> </body> </html> |
0.html
<html></html> |
上面代码中有 4 个主页面
main1.html、main2.html、main3.html、main4.html,分别对应本文分析的
4 中情况,每组代码均包含两个 DIV 元素【div1】与【div2】,其中初始状态【div1】包含 IFRAME 元素【ifr1】及【ifr2】,【div2】中为空。
【ifr1】引入了子页面 "sub.html" ,【ifr2】引入了子页面 "0.html" 。通过 JavaScript
将【div1】中的【ifr1】及【ifr2】移动到【div2】内。但是 4 个主页面采取了不同的移动方式。
子页面中,分别判断了 33 个对象的状态,若存在该对象,则显示“OK" 及对象类型,否则显示 "FAIL" 。
在本地构建 Web 服务器1,将测试代码放入服务器进行测试。
window.onload 之前,通过 innerHTML 方法改变 IFRAME 元素在文档树中的位置 | window.onload 之前,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置 | window.onload 之后,通过 innerHTML 方法改变 IFRAME 元素在文档树中的位置 | window.onload 之后,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
IE6 IE7 IE8 Opera | Firefox | Chrome Safari | IE6 IE7 IE8 Opera | Firefox | Chrome Safari | IE6 IE7 IE8 Opera | Firefox | Chrome Safari | IE6 IE7 IE8 Opera | Firefox | Chrome Safari | |
parent | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr1") | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr1").contentWindow | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById( "ifr1") .contentWindow.document | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr1") .contentWindow.history | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr1") .contentWindow.location | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr1") .contentWindow.navigator | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr1") .contentWindow.screen | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr1") .contentWindow.alert | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") .contentWindow | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") .contentWindow.document | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") .contentWindow.history | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") .contentWindow.location | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") .contentWindow.navigator | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") .contentWindow.screen | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.document .getElementById("ifr2") .contentWindow.alert | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.frames | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK | OK |
parent.frames["ifr1"] | OK | OK | OK2 | OK | OK | OK | OK | OK | OK2 | OK | OK | OK |
parent.frames["ifr1"].document | OK | OK | FAIL | OK | OK | OK | OK | FAIL | FAIL | OK | FAIL | OK |
parent.frames["ifr1"].history | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr1"].location | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr1"].navigator | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr1"].screen | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr1"].alert | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr2"] | OK | OK | OK2 | OK | OK | OK | OK | OK | OK2 | OK | OK | OK |
parent.frames["ifr2"].document | OK | OK | FAIL | OK | OK | OK | OK | FAIL | FAIL | OK | FAIL | OK |
parent.frames["ifr2"].history | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr2"].location | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr2"].navigator | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr2"].screen | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
parent.frames["ifr2"].alert | OK | OK | FAIL | OK | OK | OK | OK | OK | FAIL | OK | OK | OK |
注1. Chrome 中认为本地页面为跨域,IFRAME 元素父子页面之间的脚本交互是不安全的,会在控制台提示错误:Unsafe JavaScript attempt to access frame with
URL [XXX] from frame with URL [XXX]. Domains, protocols and ports must match.
注2. 与其他浏览器不同,Chrome 和 Safari 此时虽然返回一个有效对象,但此对象类型不是 [window] 而是 [HTMLIframeElement]。
从上表中的结果可见,通过 document.getElementById("IFRAME").contentWindow 的方式获取 IFRAME 元素引入子页面的 window 对象,各浏览器均没有任何问题。而 window.frames 方式则产生了差异:
可见,对于 window.frames 方式,使用情况 2,即 window.onload 之前,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置不会出现兼容性问题。
根据上面所得的结果,推荐使用 document.getElementById("IFRAME").contentWindow.document 获取 IFRAME 元素内页面的 document 对象,且对于在文档树中移动位置后的 IFRAME 元素也有很好的兼容性。同时应避免对跨域的父子页面交互。
操作系统版本: | Windows 7 Ultimate build 7600 |
---|---|
浏览器版本: |
IE6
IE7 IE8 Firefox 3.6.7 Chrome 6.0.472.0 dev Safari 5.0 Opera 10.60 |
测试页面: |
main1.html
main2.html main3.html main4.html |
本文更新时间: | 2010-07-22 |
IFRAME parent frames collection 文档树 移动 交互 contentWindow