今天我们来谈谈一个页面的内嵌某个页面的问题,已经被内嵌的网页的高度自适应问题以及内容的溢出导致的滚动条的隐藏的问题,首先我们应该先了解什么是跨域和同域的问题
何为跨域和同域
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js | 同一个域名下 | 允许 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同个域名下,不同文件夹下 | 允许 |
http://www.a.com:8000/a.js http://www.a.com/b.js | 同个域名下,不同端口下 | 不允许 |
http://www.a.com/a.js https://www.a.com/b.js | 同一个域名下,不同协议下 | 不允许 |
http://www.a.com/a.js http://70.32.92.74/b.js | 域名和域名对应的IP | 不允许 |
http://www.a.com/a.js http://script.a.com/b.js | 主域名相同,子域名不同 | 不允许 |
http://www.a.com/a.js http://a.com/b.js | 同域名下,二级域名不同 | 不允许 |
http://www.cnblogs.com/a.js http://www.a.com/b.js | 不同域名 | 不允许 |
同域 contentWindow
在同域的情况下,我们可与通过js代码来获得iframe对应的页面的高度,同时将高度传给父页面即可,若跨域则会报错,
document.getElementById(id).contentWindow
获得子页面的高度会后。父页面的就可以显示页面的实际高度和内容。
parent.window
跨域 minway
跨域的特点:网页的协议(Protocol), 你的host(是否相同)就是指url的首部。
强调的是:url首部必须一样,比如:二级域名或者IP地址,都算是跨域.
其实跨域的高度自适应原理并不难,其中需要一个代理页面的来协调一下的数据的传输工作。
在子页面中建一个代理页面是第一步。在父页面中嵌套子页面,在子页面中嵌套一个与父页面的同域的代理的页面,因为父页面和代理页面是同域的,所以他们之间可以很容易实现通信。
子页面会定时将自己页面的高度赋值与代理页面的URL后,代理页面拿到自身URL的数据并传递给父页面,父页面改变子页面所在的iframe高度,进而达到iframe的高度自适应。
注意: 当然,要做到跨域高度自适应还有一个前提,你必须能操作子页面,也就是说子页面也是你能控制的,若是想把baidu.com作为子页面而达到高度自适应这个就无法实现了。
在子页面中添加代码:
/**
* midway 页面高度自适应代码
* 在父页面iframe的src地址后加上midway_url作为线索
* 一可实现功能,二亦是实现动态加载js,实现此功能的通用
* midway_url 为需要嵌入目标页面实现功能的js地址
*/
;(function() {
var str_midway_url = "midway_url";
//从URL中获取midway_url
var midway_reg = new RegExp(str_midway_url + "=([^&]*)(&|$)");
var midway_res = window.location.search.match(midway_reg);
//从Cookie中获取midway_url
var cookies = document.cookie;
var offset = cookies.indexOf(str_midway_url);
//若URL中存在,则获得并存入Cookie
//若Cookie中存在,则获取
var midway_url = '';
if (midway_res) {
midway_url = unescape(midway_res[1]);
document.cookie = str_midway_url + "=" + midway_url;
} else if (offset != -1) {
offset += str_midway_url.length + 1;
var end = cookies.indexOf(";", offset);
end = (end != -1) ? end : cookies.length;
midway_url = cookies.substring(offset, end);
}
//将目标地址的js引入页面中,实现功能
if (midway_url) {
var dom_script = document.createElement("script");
dom_script.src = midway_url;
document.body.appendChild(dom_script);
};
})();
父元素父页面通过iframe标签引入子页面, 在子页面的URL后加上额外的一个参数midway_url
。在子页面的js中加入以上代码,其核心代码为一个判断语句:若url或者cookie中存在此参数,则继续下一步,若不存在则不再继续。
一般的关于iframe的代码中,都是在子页面中通过iframe直接引入代理页面,会有以下弊端:
- 代码冗余。若是直接访问子页面,则子页面的代理页面便成了冗余代码。
- 缺乏灵活性。若是子页面还会被其他其他页面所访问,则再无法实现自适应功能。
通过URL参数将minway.js传至给子页面,子页面从此判断自己是否被引用了。子页面创建
某些页面因为某些关系需要自我刷新,使得URL中的参数丢失,故将midway_url存入cookie中持久化保存。
被引入子页面的midway.js代码
在这里插入代码片
/**
* 这是被子页面引用的js - midway.js
* midway.js 必须与 midway.html 在同一目录
*/
;(function() {
var midway = {
init: function() {
var str_midway_id = "midwayAgentPage";
var midway_url = this.getMidwayUrl();
this.createMidwayIfr(str_midway_id, midway_url);
this.setHeight2Ifr(str_midway_id, midway_url);
},
//在子页面中创建代理iframe,其指向与父页面同域的midway.html
createMidwayIfr: function(str_midway_id, midway_url) {
var midway_ifr = document.createElement("iframe");
midway_ifr.id = str_midway_id;
midway_ifr.src = midway_url;
midway_ifr.style.display = "none";
document.body.appendChild(midway_ifr);
},
//定时将目标高度值附加到代理Iframe的src地址#之后
setHeight2Ifr: function(str_midway_id, midway_url) {
setInterval(function() {
//此处获取目标高度,不宜直接取body高度,应在内容之外套一层div置于body内
var target_height = document.getElementsByTagName("div")[0].scrollHeight;
var midway_ifr = document.getElementById(str_midway_id);
if (midway_ifr) {
midway_ifr.src = midway_url + '#' + target_height;
}
}, 66);
},
//从cookie中得到midway_url return http://.../midway.html
getMidwayUrl: function() {
var str_midway_url = "midway_url";
var cookies = document.cookie;
var offset = cookies.indexOf(str_midway_url);
var midway_url = '';
if (offset != -1) {
offset += str_midway_url.length + 1;
var end = cookies.indexOf(";", offset);
end = (end != -1) ? end : cookies.length;
midway_url = cookies.substring(offset, end);
}
if (midway_url) {
//原midway_url为...midway.js,此处改为...mindway.html
return midway_url.slice(0, midway_url.lastIndexOf("/")) + "/midway.html";
}
}
};
midway.init();
})();
midway.js 的主要的功能在于根据midway_url, 在子页面创建iframe引入midway.html,使用定时器定时将子页面的实际高度赋值到iframe的src之后。
子页面中被引入的midway.html代码
<!DOCTYPE html>
<html>
<head>
<tilte>Midway</title>
</head>
<body>
<script>
window.onload = function(){
//获得父页面的中的iframe
var ifr = parent.parent.document.getElementById('myframe');
//定时从url中获取到目标的数据
//并赋予目标iframe相应的高度,实现自适应
setInterval(function(){
var h = lcoation.hash ? location.hash.substring(1):0;
if(h) ifr.style.height = h + 'px';
}, 66);
};
</script>
</body>
</html>
midway.html 相当于一个中转站,由于minway.html与父页面同域可以互通信,故通过Minway.html实时改变父页面中的iframe的高度。
父页面中关于iframe的代码如下:
<iframe id="myframe" name="myframe" width=100% height=100%
frameborder=0 marginheight=0 marginwidth=0 scrolling="no">
</iframe>
<script>
;(function(){
//此处为midway.js的URL
//注意:midway.js与midway.html应在同一文件夹
var midway_url = "http://.../midway.js";
//此处将midway.js地址添加到目标页面的URL后
document.getElementById("myframe").src("http://...&midway_url=" + midway_url);
})();
</script>
document.domain
主要解决:
//统一域名,不同二级域名。 跨域
http://www.a.com/a.js
http://a.com/b.js
若是在同一个主域不同的子域中的情况下,可以通过js对主域的设置来实现相互通信。
document.domain = “同主域名”
设置之后便可以使用同域情况下的方法拉实现页面的自由通信。
//b.html是以iframe的形式嵌套在a.html中
//www.index.com上的a.html
document.domain = 'index.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.index.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
// 在这里操纵b.html
alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};
//script.index.com上的b.html
document.domain = 'index.com';
默认情况下document.domain是指window.location.hostname,主域名指:不带www的hostname; 带上www或者其他的前缀,就是二级域名或者多级域名。
另外还可以使用iframe和location.hash,不过由于技术out了,这里就不做介绍了。
window.name
window.name 属性可设置或返回存放窗口的名称的一个字符串。利用这个属性做iframe跨域传值是很方便的。
其原理与midway的相似,midway利用一个与父页面同域的代理页面,通过改变其location.hash实现跨域传值,而这里这是通过改变window.name实现跨域传值,本质上都是通过代理iframe作为中介来实现的。
location.hash能传递的数据非常有限。
window.name可以传递更多的数据(大小一般为2M,IE和firefox下可以大至32M左右),数据格式可自定义(JSON)。
H5的CDM跨域与iframe
如果你设置的iframe的域名和你top window的域名完全不同。 则可以使用CDM(cross document messaging)进行跨域消息的传递。
- 发送消息:使用postmessage方法
- 接受消息:监听message方法
该方法挂载到window对象上,即,使用window.postmessage()调用.
该方法接受两个参数:postMessage(message, targetOrigin):
message: 就是传递给iframe的内容, 通常是string,如果你想传object对象也可以。
希望不要直接传Object。 如果有条件,可以使用是JSON.stringify进行转化。这样能保证不会出bug.
targetOrigin: 接受你传递消息的域名,可以设置绝对路径,也可以设置"“或者”/"。 表示任意域名都行,"/"表示只能传递给同域域名。
<iframe src="http://tuhao.com" name="sendMessage"></iframe>
//当前脚本
let ifr = window.frames['sendMessage'];
//使用iframe的window向iframe发送message。
ifr.postmessage('give u a message', "http://tuhao.com");
//tuhao.com的脚本
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == 'http://tuhao.com') {
if (e.data == 'give u a message') {
e.source.postMessage('received', e.origin); //向原网页返回信息
} else {
alert(e.data);
}
}
}
当targetOrigin接受到message消息之后,会触发message事件。 message提供的event对象上有3个重要的属性,data,origin,source.
data:postMessage传递进来的值
origin:发送消息的文档所在的域
source:发送消息文档的window对象的代理,如果是来自同一个域,则该对象就是window,可以使用其所有方法,如果是不同的域,则window只能调用postMessage()方法返回信息