【技术研究】如何动态获取跨域iframe高度
引言
iframe是一个“好东西”,但是又会带给你很多头疼的“问题”,特别是在ios的兼容性问题。在ios当中,iframe里的页面不会随着外层的网页大小自适应弹性缩放。相比之下,PC浏览器浏览器和安卓的浏览器则是可以实现缩放,这导致了差异性。这时候第一时刻,想到的是兼容的写法。专门针对ios专门设置iframe的scrolling属性为“no”,其他浏览器为“yes”,如下方源码。但是如果iframe子页面中存在�响应式部件tab,高度进行变化,则会引起重绘重排,导致页面突然跳到顶部。
html, body{
height: 100%;
}
#url-wrapper{
margin-top: 51px;
height: 100%;
}
#url-wrapper iframe{
height: 100%;
width: 100%;
}
#url-wrapper.ios{
overflow-y: auto;
-webkit-overflow-scrolling:touch !important;
height: 100%;
}
#url-wrapper.ios iframe{
height: 100%;
min-width: 100%;
width: 100px;
*width: 100%;
}
function create_iframe(url){
var wrapper = jQuery('#url-wrapper');
if(navigator.userAgent.match(/(iPod|iPhone|iPad)/)){
wrapper.addClass('ios');
var scrolling = 'no';
}else{
var scrolling = 'yes';
}
jQuery('
上述的兼容写法能解决部分网站的问题,但是如果是响应�式网页,页面跳动的情况还是会出现问题的。
随着技术的发展,iframe一般都是萎了满足跨域的页面。受限于浏览器的同源政策,父页面是没法跨域获取子网页的高度或者宽度。这时候,我们可能考虑将iframe的高和宽“定死”。跨域交换iframe内外的数据的方法有以下两种,一种是中间代理页面,一种是h5的API--postMessage。
中间代理页面
参考iframe高度自适应的6个方法的最后一种方法,这种方法是建立了在两个页面中一个中间代理层。原理很简单,用代理层网页地址的hash值传高度和宽度。假设www.a.com域名下的一个页面a.html要包含www.b.com下的一个页面b.html。这时,我们需要在a域名下添加一个agent.html,代理层的代码如下,放置在自己的服务器。
//agent.html
而它是被iframe目标页面所引用,iframe把高度和宽度值组织好到代理页面的链接。由于链接的调用不受跨域的限制,也算是走了个“后门”,把你想要的值“偷偷”传到代理页面上。而代理页面和主页面同源,不构成跨域,所以避免了浏览器的跨域限制。我们还需要在iframe目标页面添加一段代码,就是把添加一个iframe把数据往链接上拼接。在b.html的尾部加上这段js。
//b.html
(function autoHeight() {
var b_width = document.body.clientWidth;
var b_height = document.body.clientHeight;
var agent = document.getElementById("agent");
agent.src = agent.src + "#" + b_width + "|" + b_height; // 这里通过hash传递b.htm的宽高
})();
而在a.html还是原封不动的那个iframe就可以了。
源码参考brandonxiang/iframe-height。
postMessage
有些人觉得上面的方法非常难理解,因为中间代理层的缘故,增加了请求量,影响了加载�效率。
随着HTML5 API的发展,postMessage是不同的html页面之间进行数据通信的方法,大大简化了上述方法的步骤。
在b.html中添加一段代码,在它加载完成后,往父页面跨域发送自己的高和宽,并且可以限制你发送的父网站的ip地址,大大保证安全性。
//b.html
document.addEventListener('DOMContentLoaded', function () {
var tbody = document.body
var width = tbody.clientWidth
var height = tbody.clientHeight
window.parent.postMessage({ height: height, width: width }, '*')
}, false)
还需要在a.html网站添加一个事件监听,获取iframe内的b.html发送的高与宽,从而设置父页面的iframe的高与宽。
//a.html
var frame = document.getElementById('other')
window.addEventListener('message', function(e){
frame.style.height = e.data.height+'px'
frame.style.width = e.data.width+'px'
})
源码参考brandonxiang/iframe-height。
总结
相比之下,第二种方法会比较简单和有效。但是由于跨域限制,你不得不要求对方添加一段代码去“消除”跨域限制,也是出于安全性不得已的实现方法。
总的来说,iframe在移动端受非常多的限制,尽可能地慎用。
原博客地址
团队GITHUB