这篇文章发布于 2010年12月7日,星期二,22:30,归类于 JS实例。 阅读 185088 次, 今日 6 次 27 条评论
by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=1294
一、前言碎碎念
我从来对iframe就没有什么好感,对其基本上是不屑一顾。但是人在江湖,身不由己。经理发话,新功能使用iframe
实现,没办法,只好折腾,两大烦人的东西,一是带遮罩的弹框提示,而是iframe
高度问题。前一个烦人的问题使用其他形式的提示来规避,后一人扰人的问题确实没有什么经验,花了点时间折腾了下,基本上实现了效果,跨域没问题,兼容性也没问题,于是,写个小文备忘下,下次再使用的时候就到这儿拷贝核心代码。
口碑UED有篇大米的“再谈iframe自适应高度”一文,可以看看,虽然貌似兼容性没有个调调。此文评论有个如下的链接地址:http://css-tricks.com/examples/iFrameResize/crossdomain.php,跨域且比较兼容的iframe高度定时自动变化的demo,但是,此demo中的js像个老太太一样啰哩吧嗦,裹脚布般又臭又长,于是,对js脚本重新修身整形,把老太太变成了苗条妙龄少女。
二、原理简述
本文展示的实现方法需要父页面和框架子页面相互配合。框架页面的任务就是向父页面传递其高度值,父页面的任务就是获取这个高度,然后改变iframe
的高度。这个道理不难理解,儿子想买双增高鞋,但是由于没有经济实力买不起,于是就告诉他的老爸:“老爸,我要买双40码的增高20厘米的增高鞋”,老爸收到了这个信息,就可以掏钞票给儿子买鞋让儿子增高。
关键是这个讯息如何传递。因为这个老爸是后爸(跨域),儿子心理上有障碍,说不出口。这时候,就需要媒介来帮忙传递讯息,例如儿子的偶噶桑(お母さん)。那么,在本文中,这个协助传递高度信息的媒介是什么呢?答案就是地址栏的锚点。如下图:
将高度以如下锚点形式传递:
#height=372
iframe
页面内部通过window.top.location
属性修改父页面的地址栏地址,从而将带有高度值的地址传递过去。地址栏地址在只增加锚点的情况下是不会刷新页面的、或是产生跳转什么的。
在父页面,需要设定一个定时器,例如每200毫秒去获取iframe
的高度,如果高度改变,则取修改iframe
的高度。您可以会对此做法的效率有所疑问,根据大米的测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。所以,对于效率基本上不用担心。
三、iframe页面跳转和无跳转实例
通过window.top.location修改父页面的地址栏地址,而不刷新页面,显然是需要得知父页面的页面绝路地址的。同样可以通过window.top.location获取,一了百了。
于是,父子在地址栏和锚点媒介帮助下打情骂俏,产生交流与互动,实现高度自适应的交互。
以下就是实例了。
您可以狠狠地点击这里:iframe高度动态自适应demo(无跳转)
你可以继续狠狠地点击这里:iframe高度动态自适应demo(跳转)
这两个实例父页面的js代码和iframe页面中的都是一样的,所以,统一展示,如下:
首先是子页面,子页面的任务就是传递高度而已,假设现在已经得到iframe
当前的页面高度是1294(单位像素,省略)。则核心部分的js代码就是:
//此处window.top.location获取主页面地址的方法有跨域权限的问题,替代方法参见下面的补充。
//或者这里直接使用死地址,即hostUrl = "http://www.host.com/",这是没有任何跨域的问题的。
var hostUrl = window.top.location.toString().split("#")[0];
if (hostUrl) {
hostUrl += "#height=" + 1294;
window.top.location = hostUrl;
}
补充于2010-12-08
根据evonli的建议与提醒,iframe
页面的高度传递不需要上面这么多代码,直接改变hash就可以了,如下:
window.top.location.hash = "#height=" + 1294;
但是,在IE浏览器下(以及Chrome下),貌似此方法,不支持跨域的情况(会报权限错误)。看来可能还是得使用iframe的src传递父页面地址,后者是通过cookie,或者其他形式,或是是写死的页面地址等形式。
目前看来,貌似只有(window.top.location = 父页面地址 + 锚点)无兼容性问题,且支持跨域。所以,我开始理解为何crossdomain.php父页面的地址要通过iframe
的src
地址传递的了。但是,此方法似乎只适用于iframe
页面无跳转的情况。因为发生跳转后,iframe
地址就变了。
通过iframe
传递父页面地址方法类似下面的代码,其中iframe
指iframe
的DOM对象。
var href = window.location.href, index = href.indexOf("#"); if (index !== -1) { href = href.slice(0, index); } iframe.src = iframe.src + "#" + href;
iframe
子页面可以通过:
window.location.hash.slice(1);
获得父页面的地址栏的绝对地址。然后,就是改变父页面的地址:
var hostUrl = window.location.hash.slice(1); hostUrl += "#height=" + 1294; window.top.location = hostUrl;
//zxx:补充内容结束
下面是改变iframe
的高度值, 理论上,则iframe
以通过锚点附了高度值的url
地址应该类似下面,http://www.zhangxinxu.com#height=1294,于是工作很简单,就是得到这个1294就可以了,于是有类似下面的代码:
var iframeHeight = function() { var hash = window.location.hash.slice(1); if (hash && /height=/.test(hash)) { iframe.height = hash.replace("height=", ""); } setTimeout(iframeHeight, 200); }; iframeHeight();
最后就有类似下面的效果,默认iframe
高度120
:
点击iframe页面中的“显示图片”按钮后,很快的,iframe高度自动跟随增加,如下图所示:
四、开心网的做法
开心网第三方开发的组件也是以iframe
框架的形式嵌入的。其高度自适应实现原理大致如下。
内嵌的iframe
动态生成一个以开心网提供的页面地址的高宽为0
且隐藏的iframe
,此iframe
页面地址与开心网主页面是同域的,于是,其中iframe
页面内部的脚本就可以对主页面进行操作了(动态改变第三方iframe
的高度)。
var t = document.createElement("div"); t.innerHTML = '<iframe style="display:none;" src="http://www.kaixin001.com/interface/domain_proxy.php? para=1294&type=3'" scrolling="no" height="0" width="0"></iframe>'; document.body.appendChild(t.firstChild);
五、结语
本着简单示范的目的,文中展示的代码算是相对比较简洁的。但是,实际使用的时候,要考虑一些细节,或是性能上的调整。例如,缓存当前高度,只有高度改变才去修改iframe的高度(这个实例中并没有体现)。
总的来说应该是相当易懂的。window.top.location
为中介,iframe
把高度亦锚点的形式告知父页面,父页面通过此高度修改iframe
的高度值。寥寥十几行js代码,没有什么复杂逻辑和处理,一些简单的字符串处理。
最后,对iframe
基本上没有什么研究,所以文中可能有表述不准确的地方,或是实现方法上有潜在问题,欢迎大家指正,不甚感谢。就这些。
本文为原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=1294
(本篇完)
- HTML5 postMessage iframe跨域web通信简介 (0.279)
- iframe和HTML5 blob实现JS,CSS,HTML直接当前页预览 (0.279)
- 深入Node.compareDocumentPosition API (0.279)
- 浏览器IMG图片原生懒加载loading="lazy"实践指南 (0.279)
- css行高line-height的一些深入理解及应用 (0.232)
- CSS float浮动的深入研究、详解及拓展(一) (0.232)
- CSS float浮动的深入研究、详解及拓展(二) (0.232)
- :after伪类+content内容生成经典应用举例 (0.232)
- 小卖弄:字符上下半截的高亮显示 (0.232)
- js页面滚动时层智能浮动定位实现(jQuery/MooTools) (0.198)
- 利用重绘解决IE下JS交互产生的定位重叠等棘手bug (RANDOM - 0.044)
跨域的情况下,如果不能修改iframe内部的代码 怎么才能自适应高度呢
在 iframe 嵌入的页面内部, 用 window.frameElement 可以直接获取父页面的该 iframe 元素
iframe 与 外层 通讯,使用postMessage,不跨域
张老师,我这边目前想弄一个三层iframe嵌套啊,不知道从何下手。最终要获取的是孙子iframe的高度,但孙子的网页内容是ajax异步回调出来的数据。
用这个方法会出现点两次后退按钮才能返回上一页的问题,请问有什么好的解决办法吗?
张老师,有个iframe的问题请教下你,我们在用iframe 100%嵌入第三方的内容时,发现在iphone5以下的一些手机上遇到iframe里的内容超出iframe宽度的问题。搜到的解决办法是这个 http://stackoverflow.com/questions/23083462/how-to-get-an-iframe-to-be-responsive-in-ios-safari 的确也解决了我们的问题,但是其中的原理不是特别明白,想请张老师解答下。最难以理解的就是 safari下*width和scrolling=”no”的情况,简直反人类。。。
一直最近常关注博客,没留过言,看到今天发现,博主确牛逼,感觉以前自己遇到的一些问题,在博客里都能找到解决方法,大赞,
给iframe设置了固定高度在chrome和安卓机下面显示正常,但是在ios下面并没有效果高度会跟随里面内容自动撑高。
确实是这样的,ios下无论怎么设置ifram的高度都没用
大神,有个问题要请教下,就是嵌套的iframe里有个弹出框,但是其遮罩层不能遮住整个屏幕,该怎么处理呢
使用母页面的弹出层对象(使全局可访问)即可。
iframe如何在ios上自适应,最近的一个项目用到引入其他页面,显示不正常,严格说是把手机卡死,安卓上正常适应
坑爹啊 ios高度只有设置的一半大小 已经半天了 还没结果
这样用了以后 高度可以自动加长了 但是再变短怎么回不去了啊??求助~~
。。。博主每篇精品,恨不得偏偏珍藏。
“而是iframe高度问题”错别字了
顶!
确实,我这边第二个demo也是在chrome下面没有效果
第二個demo chrome下沒效果
过滤了?再发代码:
《iframe src=”iframe-page-fresh-home.html” name=”testIframe” scrolling=”no” frameborder=”0″ width=”100%” onload=”this.height=window.frames[‘testIframe’].document.body.scrollHeight;” style=”border:solid 1px #ccc;”》《/iframe》
不会吧,自适应高度都这么麻烦吗?
这样不就可以自适应高度了?
改top hash影响滚动条~~~
在跨域的情况下,子页面是不能直接改window.top.location.hash的,
iframe跨域应该子页面通过iframe引用一个父页面同域的跨域文件,通过跨域文件与父页面传递参数
推荐看下这篇:http://kjah.javaeye.com/blog/771797 里的:2. 通过iframe实现跨域。
为何网址不能访问?
-_-!!后爸
window.top.location.hash=”#xxx=xxx” 也可以吧?有兼容问题么?
@evonli 确实是可以改进的地方,但是貌似在IE浏览器下会报没有权限的错误!