Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.【技术研究】如何动态获取跨域iframe高度 #2

Closed
brandonxiang opened this issue May 20, 2017 · 0 comments
Closed

2.【技术研究】如何动态获取跨域iframe高度 #2

brandonxiang opened this issue May 20, 2017 · 0 comments

Comments

@brandonxiang
Copy link
Member

brandonxiang commented May 20, 2017

撰稿人:项伟平

引言

iframe是一个“好东西”,但是又会带给你很多头疼的“问题”,特别是在ios的兼容性问题。在ios当中,iframe里的页面不会随着外层的网页大小自适应弹性缩放。相比之下,PC浏览器浏览器和安卓的浏览器则是可以实现缩放,这导致了差异性。这时候第一时刻,想到的是兼容的写法。专门针对ios专门设置iframe的scrolling属性为“no”,其他浏览器为“yes”,如下方源码。但是如果iframe子页面中存在�响应式部件tab,高度进行变化,则会引起重绘重排,导致页面突然跳到顶部。

<div id="url-wrapper"></div>
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>', {
        src: url,
        id:  'url',
        frameborder: 0,
        scrolling: scrolling
    }).appendTo(wrapper);
}

上述的兼容写法能解决部分网站的问题,但是如果是响应�式网页,页面跳动的情况还是会出现问题的。

随着技术的发展,iframe一般都是萎了满足跨域的页面。受限于浏览器的同源政策,父页面是没法跨域获取子网页的高度或者宽度。这时候,我们可能考虑将iframe的高和宽“定死”。跨域交换iframe内外的数据的方法有以下两种,一种是中间代理页面,一种是h5的API--postMessage。

中间代理页面

参考iframe高度自适应的6个方法的最后一种方法,这种方法是建立了在两个页面中一个中间代理层。原理很简单,用代理层网页地址的hash值传高度和宽度。假设www.a.com域名下的一个页面a.html要包含www.b.com下的一个页面b.html。这时,我们需要在a域名下添加一个agent.html,代理层的代码如下,放置在自己的服务器。

//agent.html
<script type="text/javascript">
    var other = window.parent.parent.document.getElementById("other");
    var hash_url = window.location.hash;
    if (hash_url.indexOf("#") >= 0) {
        var hash_width = hash_url.split("#")[1].split("|")[0] + "px";
        var hash_height = hash_url.split("#")[1].split("|")[1] + "px";
        other.style.width = hash_width;
        other.style.height = hash_height;
    }
</script>

而它是被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就可以了。

<!--a.html-->
<iframe src="./othersite.html" id="other" frameborder="0" scrolling="no" style="border:0px;"></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在移动端受非常多的限制,尽可能地慎用。

欢迎订阅我们的博客,请点击上方的watch按钮噢。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant