您的位置:知识库 » Web前端

iframe诡异的内容消失问题

来源: 宅居  发布时间: 2011-01-20 23:54  阅读: 5097 次  推荐: 0   原文链接   [收藏]  
摘要:该文章讲解iframe诡异的内容消失问题,希望对您有所帮助。

  问题描述

  不得不承认,这是一个非常诡异的问题,以下步骤可以重现问题:

  1. 用IE打开这个测试页面,确认页面上有个iframe,里面显示着abc三个字符。
  2. 把这页面加进收藏夹。
  3. 重新打开IE。
  4. 从收藏夹再打开这页面 。

  如果没出问题的话,你会发现页面上虽然还有iframe,但是abc消失了。更准确、详细地说,前后2次的页面主要有以下区别:

  • 从视觉上来说,页面中的abc字符消失了。
  • 从DOM结构上看,iframe中的body元素内没有任何内容。
  • 从iframe的右键-属性上看,第一次页面上iframe的地址是父页面的URL,第二次则变成了about:blank。

  以下是这个页面的源码,是从遇上问题的页面中不断分离、简化,最后形成的一个最简的重现方案:

!DOCTYPE html
html
head
meta charset="utf-8" /
titletest/title
/head
body
script type="text/javascript"
var text = 'abc',
script
= 'var d = document; ' +
'd.open(\'text/html\', \'replace\'); d.write(parent.text); d.close();',
html = 'iframe id="abc" name="abc" ' +
'src="javascript:void((function() {' + script + '})())"/iframe';
document.write(html);
/script
/body
/html

  解决方案

  首先,这个页面虽然简单,但其中用到了几个很恶心人的东西:

  • document.write。
  • javascript:伪协议。

  如果有办法避免使用这两者的话,就可以忽略这个问题。但是如果必须使用javascript:伪协议来向iframe中输出内容的话,将以上代码改为如下形式可以解决问题:

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
//插入到需要的位置
iframe.contentWindow.location = 'javascript:void((function() {' + script + '})())';

  具体的区别是,从直接使用document.write来输出iframe,变为了使用createElement创建iframe,随后使用iframe的location来采用javascript:伪协议输出具体内容。

  起因

  由于原本这段代码不是我写的,所以在发现这个问题的时候,我也有过疑问,为啥要这么写呢?难道下面的方式不是更好吗:

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
//插入到需要的位置
iframe.contentWindow.document.write('abc');

  然而这一段代码的注释中写是IE在修改了document.domain进行提权后,iframe会出现跨域问题。所以以下代码,其中在IE中是会报错(拒绝访问)的:

//假设当前域是www.tt.com
document.domain = 'tt.com'; //domain提权
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
//插入到需要的位置
iframe.contentWindow.document.write('abc');

  至于解决的办法,就是在iframe的src中,使用javascript:伪协议输出内容,当然输出的时候要注意,在iframe的document执行open以后,加上一句代码,把iframe的docuemnt.domain也进行提权,提升到和父页面相同,这样iframe和父页面就是同域的,可以进行交互了。

  正是因为IE存在着这样的问题,为了解决这个问题,原有代码中使用了document.write输出带src属性的iframe元素,从而引发了另一个问题……

  猜测

  那么这个问题是因为什么原因引起的呢?首先对页面的执行过程进行分析,大致是这么几步:

  1. 解析script标签,执行内容。
  2. document.write向文档流中输出一个iframe元素。
  3. iframe中,使用document.write输出文字。

  从页面的视觉效果而言,iframe是存在的,但iframe里面的内容消失了。这让人很自然地联想到,第2步已经执行了,但由于浏览器缓存iframe的内容等原因,第3步并没有执行。

  为了测试这个情况,比较简单的方法就是在iframe的src里的javascript代码中添加一个断点,我的选择是在d.close()这一句之前,加上了一行代码:alert(d.body.innerHTML);

  经过以上的修改,执行的结果是,成功地出现了alert对话框,并且innerHTML确实存在abc字符,另外更奇怪的是,经过alert,abc出现在了iframe中。

  也就是说,第3步是确实地执行了,但是在没有alert的情况下,却没有在界面上产生任何效果。综合以上的原因,联想到alert函数的一个作用是将浏览器的UI Update队列进行flush操作,因此对于完全黑盒的IE浏览器,现阶段只能猜测,在这种特殊的使用方式之下,IE丢失了UI Update队列中的部分更新,导致iframe的document并没有得到更新,因此也保留了about:blank这种地址。

0
0

Web前端热门文章

    Web前端最新文章

      最新新闻

        热门新闻