`
cuijiemin
  • 浏览: 264108 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Chrome Safari Firefox 中 IFRAME 元素在文档树中发生变化后父子页面间的某些交互方式会失效

阅读更多

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 引入。

下面分 4 种情况测试当 IFRAME 元素在文档树中发生变化对 IFRAME 内外的子页面与父页面交互的影响。

  1. window.onload 之前,通过 innerHTML 方法改变 IFRAME 元素在文档树中的位置:main1.html
  2. window.onload 之前,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置:main2.html
  3. window.onload 之后,通过 innerHTML 方法改变 IFRAME 元素在文档树中的位置:main3.html
  4. window.onload 之后,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置:main4.html

测试代码如下:

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.htmlmain2.htmlmain3.htmlmain4.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 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
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK OK OK OK OK OK OK OK OK OK
OK OK OK2 OK OK OK OK OK OK2 OK OK OK
OK OK FAIL OK OK OK OK FAIL FAIL OK FAIL OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK OK2 OK OK OK OK OK OK2 OK OK OK
OK OK FAIL OK OK OK OK FAIL FAIL OK FAIL OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
OK OK FAIL OK OK OK OK OK FAIL OK OK OK
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 方式则产生了差异:

  1. window.onload 之前,通过 innerHTML 方法改变 IFRAME 元素在文档树中的位置:
    • IE6 IE7 IE8 Firefox Opera中,子页面均可以获得移动后的【ifr1】及【ifr2】相关对象;
    • Chrome Safari中,虽然可以获取到父页面的【ifr1】及【ifr2】相关对象,但是与 IE Firfox Opera 中不同,该对象类型为 "HTMLIframeElement" ,而不是 "Window" ,所以该对象的子对象无法获取。
  2. window.onload 之前,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置:
    • 各浏览器中,子页面均可以获得移动后的【ifr1】及【ifr2】相关对象。
  3. window.onload 之后,通过 innerHTML 方法改变 IFRAME 元素在文档树中的位置:
    • IE6 IE7 IE8 Opera中,子页面均可以获得移动后的【ifr1】及【ifr2】相关对象;
    • Firefox中,在 window.onload 中移动 IFRAME 却使 IFRAME 的 window 对象中 "document" 对象失效;
    • Chrome Safari中,虽然可以获取到父页面的【ifr1】及【ifr2】相关对象,但是与 IE Firefox Opera 中不同,该对象类型为 "HTMLIframeElement" ,而不是 "Window" ,所以该对象的子对象无法获取。
  4. window.onload 之后,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置:
    • IE6 IE7 IE8 Opera Chrome Safari中,子页面均可以获得移动后的【ifr1】及【ifr2】相关对象;
    • Firefox中,在 window.onload 中移动 IFRAME 却使 IFRAME 的 window 对象中“document" 对象失效。

可见,对于 window.frames 方式,使用情况 2,即 window.onload 之前,通过 removeChild、AppendChild 方法改变 IFRAME 元素在文档树中的位置不会出现兼容性问题。

解决方案

根据上面所得的结果,推荐使用 document.getElementById("IFRAME").contentWindow.document 获取 IFRAME 元素内页面的 document 对象,且对于在文档树中移动位置后的 IFRAME 元素也有很好的兼容性。同时应避免对跨域的父子页面交互。

分享到:
评论

相关推荐

    解决IE,Firefox,chrome,safari浏览器中iframe显示高度自适应问题

    例如,在IE6中,`iframe`能够正常显示,但在其他浏览器如Firefox、Chrome和Safari中,可能出现高度过小或过大,无法正确反映`iframe`内部内容的实际高度。这不仅影响用户体验,还可能破坏网页的整体布局。 #### ...

    Chrome和Firefox插件可快速删除网页上的元素

    标题中的“Chrome和Firefox插件可快速删除网页上的元素”是指一种利用浏览器扩展来实现的网页自定义功能,用户可以通过安装特定的插件在浏览网页时去除不想要的元素,如广告、弹窗或者任何干扰视线的内容。...

    iframe和firefox的兼容。

    然而,不同的浏览器对于`iframe`的支持程度和处理方式可能存在差异,尤其是在较早版本的Firefox中,可能会遇到一些兼容性问题。本篇文章将详细探讨`iframe`在Firefox中的兼容性挑战及其解决方案。 1. **Firefox对...

    weboffice for chrome firefox

    【标题】"weboffice for chrome firefox" 涉及的是一个专为谷歌Chrome和Firefox浏览器优化的在线办公解决方案。Weboffice是一款能够提供Web端文档编辑、查看和协作功能的应用,使得用户无需安装桌面软件即可在浏览器...

    基于jQuery+CSS3 手风琴图片折叠滑开代码(支持ie9 chrome safari firefox opera).zip

    【描述】中提到的“支持ie9 chrome safari firefox opera”意味着这个代码片段是跨浏览器兼容的,可以在这五个主流浏览器(Internet Explorer 9、Chrome、Safari、Firefox和Opera)上正常运行。在前端开发中,确保...

    iframe自适应高度,亲测完美兼容IE6-9,Chrome,Opera,firefox,safari

    因为有一个项目要用到iframe自适应高度,网上搜索了以下结果无数,不过看来看去都是那...iframe自适应高度,亲测完美兼容IE6_7_8_9,Chrome谷歌浏览器,Opera欧朋浏览器,FireFox火狐浏览器,Mac Safari浏览器等五大浏览器

    iFrame高度自适应终极解决方案(兼容IE7,8,9 Firefox3.6+,Chrome 12+)

    在网页开发中,iFrame(内联框架)是一种常见的元素,用于在页面中嵌入其他网页或内容。然而,由于浏览器之间的差异,尤其是在旧版本的IE(Internet Explorer)中,iFrame的高度自适应问题常常困扰着开发者。"iFrame...

    div被iframe遮住的几种情况及解决方法

    在前端开发过程中,DIV元素被IFRAME遮挡是一个常见的问题,尤其是当页面布局复杂或存在多层嵌套的元素时。以下将详细阐述几种DIV被IFRAME遮挡的情况,并提供相应的解决方法。 首先,要了解的是IFRAME是一种HTML元素...

    浏览器chrome opera firefox

    标题中的“浏览器chrome opera firefox”指的是三款广受欢迎的网络浏览器:Chrome(谷歌浏览器)、Opera(欧朋浏览器)和Firefox(火狐浏览器)。这三款浏览器因其高效性能、丰富的功能和用户友好的界面而在全球范围...

    用js互相调用iframe页面内的js函数

    在网页开发中,有时我们需要在一个页面中嵌入另一个页面,这就是`iframe`元素的作用。`iframe`可以让网页在不离开当前页面的情况下加载其他HTML文档,从而实现内容的分块显示或者部分更新。在这个场景下,涉及到的一...

    webdriver_firefox_chrome

    本篇将详细介绍"webdriver_firefox_chrome"这一主题,包括WebDriver的基本概念、用途、Chrome WebDriver(ChromeDriver)与Firefox WebDriver(GeckoDriver)的特性以及它们在Selenium框架中的应用。 WebDriver是一...

    firefox 最新开发文档

    开发文档会详细介绍如何在Firefox中利用这些前沿技术。 "开发文档"是学习Firefox开发的关键。它包含了大量的教程、API参考和最佳实践。对于初学者,你可以从简单的"Hello, World"扩展开始,逐步了解如何添加自定义...

    support-protocol-v8-chrome-15-firefox-6

    标题“support-protocol-v8-chrome-15-firefox-6”揭示了这是一个与Web开发相关的资源,特别是针对HTML5的Server-Sent Events (SSE)或WebSocket协议的实现,适用于Chrome 15和Firefox 6这两个浏览器版本。...

    Chrome Extension (Chrome插件)开发官方最新文档(20190401)

    4. **浏览器动作和页面动作**:这两种是插件的UI元素,用于在浏览器工具栏显示图标,用户点击后触发相应功能。 5. **DOM操作**:通过JavaScript,插件可以对网页的DOM进行增删改查,实现网页的动态修改。 二、开发...

    让ActiveX在FireFox和Chrome等NPAPI插件接口的浏览器中运行

    让ActiveX在FireFox和Chrome等NPAPI插件接口的浏览器中上运行 这样firefox浏览器就可以正常浏览有ActiveX插件的网页,比如flash 的ActiveX控件: id="Control" TYPE="application/x-itst-activex" WIDTH="300" ...

    Selenium webDriver(chrome和Firefox)

    它与Firefox浏览器交互的方式与ChromeDriver类似。要使用GeckoDriver,你需要: 1. 下载与你的Firefox版本兼容的GeckoDriver,官方下载链接可以在[Mozilla的GitHub页面]...

    Chrome插件开发--后台监控网页并自动刷新,点击页面元素

    3. **内容脚本(Content Script)**:这些脚本会注入到用户访问的网页中,可以直接操作DOM,实现对网页元素的控制,如自动刷新和点击页面元素。 4. **浏览器动作(Browser Action)和页面动作(Page Action)**:...

    clipboard复制文本或者隐藏域到剪切板,兼容ie.chrome.firefox

    针对这个问题,`clipboard.js`应运而生,它提供了一种优雅且兼容多浏览器的方式来实现文本复制功能,包括IE、Chrome和Firefox等主流浏览器。 `clipboard.js`是一个轻量级的库,它的主要作用是简化了浏览器的剪贴板...

    selenium谷歌chrome、火狐firefox,IE浏览器驱动

    在这个主题中,我们主要关注Selenium如何与Google Chrome、Firefox和Internet Explorer(IE)这三大主流浏览器配合使用的浏览器驱动。 1. Selenium与Chrome浏览器驱动 (ChromeDriver): Selenium 通过ChromeDriver...

Global site tag (gtag.js) - Google Analytics