iframe的使用

为避免iframe的跨域问题,下面例子都是放在apache上进行的。父页面和子页面的文档类型均为:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

浏览器为chrome(版本 33.0.1750.154 m)、firefox(27.0.1)、IE10、IE7-9 (均为IE10自带的调试模式 ) 、safari(5.1.7(7534.57.2)) ,没有特意说明的都是指这些浏览器表现一致。

0、父页面和子页面的关系

1、父页面和子页面的加载顺序

2、iframe加载完毕事件

3、父页面获取子页面里的元素及window和document对象(在父页面依据子页面调整iframe的高度)

4、子页面获取父页面里的元素及window和document对象

5、父页面调用子页面方法

6、子页面调用父页面方法

7、获取子页面元素所在的iframe,不通过id

0、父页面和子页面的关系:

若某一页面grandFather.html里有个iframe,这个iframe嵌套着father.html,而father.html里有个iframe嵌套着son.html,则在son.html里window.document=window.self.document就是指son.html,window.parent.document就是指father.html,而window.parent.parent.document就是指grandFather.html,而window.top永远指最上层的窗口,此处就是grandFather.html了。

1、父页面和子页面的加载顺序:

主页面fatherPage.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">   
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
    console.log ('fatherPageBefore');
</script>
</head>
<body> 
    <iframe id='iframeid' src="sonPage.html"></iframe>
    <div id='fatherDivId'>the father page</div>
</body>
<script type="text/javascript"> 
    console.log ('fatherPageAfter');
</script>
</html>
子页面sonPage.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">   
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
    console.log ('sonPageBefore');
</script>
</head>
<body > 
 <div id='sonDivId' >the son page</div>
</body>
<script type="text/javascript"> 
    console.log ('sonPageAfter');
</script>
</html>

运行结果:fatherPageBefore-->fatherPageAfter-->sonPageBefore-->sonPageAfter。即父页面全部执行完成后才开始执行子页面。

插曲: 开始测试时不是用console.log,而是alert,发现fireflox的运行结果与其他都不一样,是fatherPageBefore-->sonPageBefore-->sonPageAfter-->fatherPageAfter,还以为firefox真的表现不一样,所以对于测试跟时间相关的,用alert不是很靠谱。

附:实践证明父页面中有多个iframe时,并不是按先后一个一个加载的,在现实环境里可以认为加载顺序是随机的 。

2、iframe加载完毕事件:

由上面加载顺序可知,要想在父页面获取子页面里的元素及window和document对象必须先判断iframe已经加载完毕。在http://www.w3schools.com/jsref/dom_obj_frame.asp中提到“ The IFrame object also supports the standard properties and events.”这其中就包括onload。

在fatherPage.html的body后的js改成

console.log (' fatherPage After');
var element = document.getElementById("iframeid"); 
element.onload=function(){console.log ('sonPageLoaded');}

运行结果: fatherPageBefore-->fatherPageAfter-->sonPageBefore-->sonPageAfter-->sonPageLoaded。即可以利用onload判断iframe加载完毕。

各浏览器均表现正常,onload在每一次重新加载(如:同一个iframe根据情况加载不同的子页面)完毕时都能触发。

 附:实践中发现onload在ie6中不保险(两个iframe只有一个触发了),用下面这样分情况后有效(IE隐形支持onload):

if (iframeObj.attachEvent){
    iframeObj.attachEvent("onload", function(){
        //do something
    });
} else {
    iframeObj.onload = function(){
        //do something
    };
}

3、父页面获取子页面里的元素及window和document对象(在父页面依据子页面调整iframe的高度):

http://www.w3schools.com/jsref/dom_obj_frame.asp中列出了iframe的property,其中有写到:

contentDocument

Returns the document object generated by an iframe

contentWindow

Returns the window object generated by an iframe

并说明了主流的浏览器都支持,没有提到它有兼容问题。

测试contentDocument(记得要放在onload事件里):

var element = document.getElementById("iframeid"); 
element.onload =function(){
    element.contentDocument.body.style.backgroundColor='blue' ;
    element.contentDocument.getElementById('sonDivId').style.backgroundColor='red' ;
}

运行结果:IE7表示无法识别contentDocument,其他浏览器正常显示。

测试contentWindow(记得要放在onload事件里):

var element = document.getElementById("iframeid"); 
element.onload =function(){
    element.contentWindow.document.body.style.backgroundColor='blue' ;
    element.contentWindow.document.getElementById('sonDivId').style.backgroundColor='red' ;
}

运行结果:正常显示。

所以为了兼容性,还是用contentWindow吧。jquery中获取子页面元素的方法是
$("#subPageDivId",document.frames('iframename').document)或$(window.frames["iframename"].document).find("#subPageDivId")

插曲:既然可以获取子页面元素来,那按道理就可以动态设置iframe的高度以适应不同的子页面了。

父页面中<iframe id='iframeid' src=" sonPage1.html"  scrolling="no"></iframe>视情况加载sonPage1.html(不带滚动条)和sonPage2.html(带滚动条) 。

测试clientHeight:

根据https://developer.mozilla.org/en-US/docs/Web/API/Element.clientHeight对Element.clientHeight的定义” the inner height of an element in pixels, including padding but not the horizontal scrollbar height, border, or margin.”,网上多理解为可视区域的大小。

element.onload =function(){   
element.setAttribute('height',element.contentWindow.document.body.clientHeight +'px');
element.setAttribute('width',element.contentWindow.document.body.clientWidth +'px'); }

运行结果:iframe重置的width都没有满足两个子页面的要求,height只有嵌入无滚动条的sonPage1.html时满足要求。也就是width表现不正常(why),height正常。

测试offsetHeight:

根据https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.offsetHeight对Element.offsetHeight的定义”

Typically, an element's offsetHeight is a measurement which includes the element borders, the element vertical padding, the element horizontal scrollbar (if present, if rendered) and the element CSS height.Non-scrollable elements (CSS overflow not set or set to visible) will have equal offsetHeight and Element.scrollHeight (is this right? scrollHeight doesn't include the border, while offsetHeight would include border). ”

运行结果:IE9-10、chrome、firefox、safari,高度均满足需要,宽度依然不可用。

             IE7-8:与clientHeight/Width时效果一样。

测试scrollHeight:

根据https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollHeight对Element.scrollHeight的定义” a measurement of the height of an element's content including content not visible on the screen due to overflow. ThescrollHeight value is equal to the minimum clientHeight the element would require in order to fit all the content in the viewpoint without using a vertical scrollbar. It includes the element padding but not its margin."。可以理解为网页的实际高度(除去margin)。

看上去是不是觉得用scrollHeight就没问题啦?......

运行结果:IE、firefox高度宽度均满足需要,chrome 、safari时iframe的设置总是按较大的那个页面不变。(即在sonPage1.html里获取的document.body.scrollHeight总是为sonPage2.html的高度)。虽然使用scrollHeight使问题有了改善,但还是不行啊......

但是如果像下面这样使用两种属性,运行结果为四种浏览器都满足需要了。

element.onload =function(){
    element.setAttribute('height',element.contentWindow.document.body.scrollHeight  +'px'); 
    element.setAttribute('width',element.contentWindow.document.body.scrollWidth +'px'); 
    element.setAttribute('height',element.contentWindow.document.body.offsetHeight  +'px');
    element.setAttribute('width',element.contentWindow.document.body.offsetWidth +'px');
}

 总结:感觉都不靠谱,建议还是用一个总的div作为子页面body的唯一子元素,在父页面直接获取这个div的高度,这样最靠谱了。

4、子页面获取父页面里的元素及window和document对象:

根据http://www.w3schools.com/jsref/prop_win_parent.asp中window对象有一个parent属性,“returns the parent window of the current window.”

所以window.parent返回父对象的window对象,如window.parent.location(可用于设置弹出新窗口)。

jquery方法:$('#parentDivId', parent.document)或$(window.parent.document).find('#parentDivId')

window.parent.document.getElementById('fatherDivId').style.backgroundColor='white';
window.parent.document.getElementById('iframeid').setAttribute('height','50px');

5、父页面调用子页面方法:

element.contentWindow.subPageFunName();

运行结果:均有效。(使用element.contentDocument.subPageFunName();均会出错。)

6、子页面调用父页面方法:

parent.fatherPageFunName();

运行结果:均有效。

7、在子页面中获取某个元素在整个页面(window.top)中相对于当前视口的偏移

如下先获取此元素的父级iframe的偏移,再加上自己的偏移就可以了。

function getIframesLeftTop(){
  var obj={left:0,top:0};
  var ws=window.self;
  while(ws!=window.top){
    wp=ws.parent;
    for(var i=0;i<wp.frames.length;i++){
      if(wp.frames[i].document==ws.document){
         obj.left+=$(wp.frames[i].frameElement).offset().left;
         //注意此处的frameElement,比如想获取父级iframe的id时:
        //wp.frames[i].frameElement.id
         obj.top+=$(wp.frames[i].frameElement).offset().top;
        ws=wp;
      }
    }
  }
  return obj;
}
原文地址:https://www.cnblogs.com/yigeqi/p/3541639.html