`
guoyiqi
  • 浏览: 1025104 次
社区版块
存档分类
最新评论

三谈Iframe自适应高度(转自:http://ued.koubei.com/?p=1217)

 
阅读更多

三谈Iframe自适应高度 By 由校

为什么是三谈

为什么是三谈呢?一是因为这真的是一个被说烂的话题,二是因为太师傅在n年前就写过这篇再谈iframe自适应高度。之所以再提该问题,是因为之前项目中确实遇到了这个问题的方方面面,有必要总结一下。希望对各位有帮助,有错误请指正。

同域、子页面高度不会动态增加

这种情况最简单,直接通过脚本获取字页面实际高度,修改iframe元素高度即可。但有二点必须注意:

如果页面内有绝对定位或者没有清浮动的元素,情况有些复杂,不同浏览器处理结果不同,甚至包括Webkit内核的浏览器,具体请看这个Demo。所以你要么进行浏览器检测,要么用Math.max计算一个最大值,要么你想别的方法。

iframe所包含页面可能非常大,需要很长的加载时间,为此直接计算高度的时候,很可能页面还没下载完,高度计算就会有问题。所以最好在iframe的onload事件中计算高度。这里还要注意的是,IE下必须使用微软事件模型obj.attachEvent来绑定onload事件。而别的浏览器直接obj.onload = function(){}也可以。

(function(){

var frame = document.getElementById("frame_content_parent"),

setIframeHeight = function(){

var frameContent = frame.contentWindow.document,

frameHeight = Math.max(frameContent.body.scrollHeight,frameContent.documentElement.scrollHeight);

frame.height = frameHeight;

};

if(frame.addEventListener){

frame.addEventListener("load",setIframeHeight,false);

}else{

frame.attachEvent("onload",setIframeHeight);

}

})();

同域、子页面高度会动态增加

原理与第一种情况一样,多一个计时器,一直检测字页面高度,当子页面高度和iframe的高度不一致时,重新设置iframe的高度。这边也可以加一个try在js出错时,加一个足够的高度。

(function(){

var _reSetIframe = function(){

var frame = document.getElementById("frame_content_parent")

try {

var frameContent = frame.contentWindow.document,

bodyHeight = Math.max(frameContent.body.scrollHeight,frameContent.documentElement.scrollHeight);

if (bodyHeight != frame.height){

frame.height = bodyHeight;

}

}

catch(ex) {

frame.height = 1800;

}

}

if(frame.addEventListener){

frame.addEventListener("load",function(){setInterval(_reSetIframe,200);},false);

}else{

frame.attachEvent("onload",function(){setInterval(_reSetIframe,200);});

}

})();

同域、子页面高度会动态增加、脚本可能完全失效

第二个例子中,考虑到了脚本出错的情况,但是万一脚本根本不执行了呢,那iframe中的内容就会因为iframe的高度不够而显示不了。为此我们通常事先设置一个足够的高度,为了前端控制方便,我觉得写在CSS文件中比较合适,需要修改时只改CSS就行了。这里我设置了selector{ height:1800px; }。需要注意的是,写在样式表里的样式,不能直接用node.style[property]来取,对于微软模型,要用node.currentStyle[property](题外话:悲剧的IE模型不支持CSS伪类),对于W3C模型,要用window.getComputedStyle(node,null)[property]来取。我这里图方便直接用了YUI。

这里又有一个问题,设置iframe的高度大于其包含页面的高度时,各个浏览器的处理不一样。例如在Firefox下,必须计算body元素的高度,而html元素的高度等于iframe的高度,然而当恰巧这个页面又有绝对定位、未清浮动元素时,又不能通过body元素来取,显然第一种方法缺点更小一些。具体请看这个Demo。

从上面这个Demo可以看到,除IE浏览器外,别的浏览器计算出来的都是iframe的高度,即CSS里设置的#frame_content_parent{ height:1800px; }。而IE计算出来的是iframe所引用页面的实际高度。

#frame_content_parent{ height:1800px; }

(function(){

var $ = YAHOO.util.Dom,

frame = $.get("frame_content_parent");

function reSetIframe(){

var frameContent = frame.contentWindow.document,

bodyHeight = Math.max(frameContent.documentElement.scrollHeight,frameContent.body.scrollHeight);

if (bodyHeight != $.getStyle(frame, "height")){

$.setStyle(frame, "height", bodyHeight + "px");

}

}

if(frame){

$.setStyle(frame,"height","auto");

setInterval(reSetIframe,300);

}

})();

跨域

这里提供一个Iframe代理的方法,简单地说一下原理。假设有3个页面,分别是主页面A.html,字页面B.html,代理页面C.html。其中A与B是跨域的,而A和C是同域的。它们的关系:A包含B,B包含C。很显然A和B,以及B和C,因为跨域不能相互通信,而A和C同域,可以相互通信。为此我们就想到让C页面告诉A页面,B页面到底有多少高。因为B和C也是跨域的不能相互通信,所以想在C页面中,直接window.parent.document.body.scrollHeight这样是行不通的,所以我们只能让B页面自己计算自身的高度,然后通过某种方法告诉C页面,再由C页面告诉A页面。这里的一个方法就是在B页面生成一个Iframe节点,然后设置它的src属性,在这个地址上附加一个参数,即B页面计算出来的高度,然后C页面就可以通过window.location获取这个地址栏中的地址,提取出高度值,通过window.top找到A页面,设置A页面的Iframe的高度。基本的原理就是这样,看代码吧:

DEMO

//B页面脚本

//任务:计算其实际高度,然后生成一个iframe节点,将高度作为代理页面C的地址的一部分赋值给Src属性

(function(){

var agent_iframe = document.createElement("iframe"),

b_height = Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);

agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe_once.html#" + b_height;

document.body.appendChild(agent_iframe);

agent_iframe.style.display = "none";

})();

//C页面脚本

//任务:获取请求地址中的高度值,将其赋值给A页面的Iframe的高度

window.top.document.getElementById("frame_content_parent").height = parseInt(window.location.hash.substring(1),10);

跨域、字页面高度动态变化

这里结合了第2、第4两种方法,我的想法是在B页面通过一个计时器,不停计算B页面的高度,一但变化,马上修改iframe标签的src属性,而C页面也有计时器不断监听src的变化,改变Aiframe标签的高度。需要注意的是仅仅修改src属性后面的锚点值(如“#1234”),页面并不会刷新,不会重新请求,这也是在C页面增加计时器的原因。

DEMO

//B页面脚本

(function(){

var getHeight = function(){

return Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);

};

var preHeight = getHeight(),

agent_iframe;

var createIframe = function(height){

agent_iframe = document.createElement("iframe");

agent_iframe.style.height = "0";

agent_iframe.style.width = "0";

agent_iframe.style.border = "none";

agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html#" + height;

document.body.appendChild(agent_iframe);

}

createIframe(preHeight);

var checkHeight = function(){

var currentHeight = getHeight();

if(currentHeight != preHeight){

agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html#" + currentHeight;

preHeight = currentHeight;

}

setTimeout(checkHeight,500);

}

setTimeout(checkHeight,500);

})();

//C页面脚本

(function(){

var preHeight = parseInt(window.location.hash.substring(1),10),

ifrmae = window.top.document.getElementById("frame_content_parent");

ifrmae.height = preHeight;

setInterval(function(){

var newHeight = parseInt(window.location.hash.substring(1),10);

if (newHeight !== preHeight){

ifrmae.height = newHeight;

preHeight = newHeight;

}

},500);

})();

这里还有另一种方案,就是让iframe每一次都重新请求,这样C页面就不需要计时器了,但是如果2次计算高度重复的话,就会导致src属性的值相同,这样浏览器就很可能不重新请求该页面了,那么C页面中的脚本也就不运行了。要修复这个问题很简单,只要在每次计算出来的src属性上增加一个随机数的参数就行了。比如http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html?temp=123123423712937#1563

//B页面关键脚本

agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html?a=" + Math.random() + "#" + currentHeight;

//C页面脚本

window.top.document.getElementById("frame_content_parent").height = parseInt(window.location.hash.substring(1),10);

Tags: iframe, 跨域

分享到:
评论

相关推荐

    参考材料_用户研究书单及网上资源.pdf

    + 19 楼 UED:http://blog.19ued.com/ + 阿里 UED:http://www.aliued.com/ + 淘宝 UED:http://ued.taobao.com/ 交互设计 * 交互设计书籍: + About Face 3 + Designing Interfaces 中文版 + 交互设计之路 ...

    动态几何实验九:动态几何与教育zjz原件.zip

    广州大学 动态几何实验九:动态几何与教育zjz原件.zip

    动态几何实验八:统计概率zjz原件.zip

    在本压缩包“动态几何实验八:统计概率zjz原件.zip”中,包含的是广州大学一门关于动态几何与统计概率课程的实验资料。这个实验旨在帮助学生理解并应用统计学的基本概念,以及如何在几何问题中运用概率理论。...

    frontEnd:前端相关

    携程: ://ued.ctrip.com/blog/ 奇舞团 新浪: : 阿里巴巴国际ued团队: : 阿里巴巴中文站: : 浙江网新恒天UED: : 360ued: ://uxc.360.cn/ 开放平台api列表: 常见参考文档 使用说明 cnpm install ...

    淘宝2011新版首页开发实践.pdf

    - [淘宝UED团队关于栅格系统的研究文章](http://ued.taobao.com/blog/2008/10/22/grid_system_research_1/) - [淘宝UED团队关于栅格系统的研究文章](http://ued.taobao.com/blog/2008/10/22/grid_system_research_2/...

    httpd.conf

    apache httpd.conf 不能执行pl文件

    前端面试宝典

    - **块级元素**:默认占据一行,可设置宽度和高度,如`div`、`p`等。 - **行内元素**:与其他元素在同一行内显示,不可直接设置宽度和高度,如`span`、`a`等。 8. **浮动元素:** - 浮动元素可以让元素脱离文档...

    SUI-Mobie—dev

    [SUI Mobile](http://m.sui.taobao.org/) 是阿里巴巴国际UED前端团队出品的移动端 __UI库__。 没有重复造轮子。主要借鉴 __Framework7__ 的形态并以此为基础,参考Ratchet、Ionic、Onsen各种不同的思路,强化功能,...

    scikit-ued:收集(超快)电子衍射和散射的算法和例程

    科学工具 超快电子衍射算法和函数的集合。... python -m pip install git+git://github.com/LaurentRDC/scikit-ued.git 安装scikit-ued后,您可以像skued一样使用任何其他Python模块。 每个版本都针对Python 3

    ecshop后台编辑器替换成ueditor编辑器

    {insert_scripts files="../js/transport.js,common.js,../js/utils.js"} ``` 替换为: ```html <script src="../includes/ueditor/fix_jquery/jquery.min.js"></script> <script src="../includes/ueditor/fix_...

    ueditor-blazor:基于UEditor和Blazor的所见即所得的富文本Web编辑器

    尤迪托·布拉泽尔基于UEditor和Blazor的所见即所得的富文本Web编辑器。 :optical_disk: 当前版本释放: 发展:用法安装套件 $ dotnet add package UEditorBlazor -v 0.1.0- * 导入js资源 <... UEd

    UI交互设计:UED产品交互设计工作流程.pdf

    《UED产品交互设计工作流程详解》 UED,全称User Experience Design,即用户体验设计,是构建高质量产品的重要环节。在互联网行业中,一个优秀的UED流程能够确保产品的顺利推进,提升用户体验,进而增强产品的市场...

    ListView实现下拉动态渲染数据

    fetch('http://ued.yihaodian.com:3001/api/70') .then((response) => response.json()) .then((data) => { this.listData = data.listData; this.len = this.listData.length; this.count = Math.ceil(this....

    用于处理和解释超快电子衍射(UED)实验数据的Matlab代码.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程...

    树型表格可以下拉折叠

    在描述中的实例链接(http://ued.pingan.com/id/demos/table/tree.jsp#example)中,我们可以看到一个实际的树型表格应用。这个例子可能包括以下功能: 1. **节点展开与折叠**:用户点击某个父节点,其子节点会以下...

    TCl工业研究院UED实习总结.doc

    TCl工业研究院UED实习总结.doc

    仿淘宝UED的wordpress主题

    【标题】"仿淘宝UED的WordPress主题"是一个专门为设计公司、个人相册和摄影网站定制的主题,它借鉴了淘宝用户体验设计团队(UED)的设计理念,旨在提供一个既美观又功能丰富的网站展示平台。 【描述】中提到的关键...

    UED设计插件

    UED(User Experience Design,用户体验设计)是互联网产品开发中的关键环节,它专注于创建易于使用、功能强大且视觉吸引力强的用户界面。UED设计插件则是设计师们为了提高工作效率、简化设计流程而开发的一类工具。...

    WEB前端与UED角色对应关系模型.pdf

    【WEB前端与UED角色对应关系模型】 在互联网行业中,WEB前端和UED(User Experience Design,用户体验设计)是两个紧密关联的领域。UED主要是关注产品前端的设计,追求的不仅仅是外观的美观,更重要的是创造出用户...

Global site tag (gtag.js) - Google Analytics