使用场景
需求
在一个H5项目的页面中以url的方式嵌入另一个项目的页面。(不得不使用iframe)
而为了兼容移动端api(封装的一个移动端api,iframe内嵌页面不生效),需要实现父子页面的通信 (使用postMessage)。
iframe使用
基本使用
直接在页面嵌套iframe标签指定src即可使用iframe。
<iframe src="xxx.html"></iframe>
常用属性
frameborder :是否显示边框,1(yes),0(no) height :框架作为一个普通元素的高度。 width :框架作为一个普通元素的宽度。 name :框架的名称,window.frames[name]时专用的属性。 scrolling :框架的是否滚动。yes,no,auto。 src :内框架的地址,可以使页面地址,也可以是图片的地址。 sandbox :对iframe进行一些列限制,IE10+支持更多属性访问: 这里
iframe高度自适应
let ifr = document.getElementById('ifr')
const deviceHeight = document.documentElement.clientHeight;
ifr.style.height = (Number(deviceHeight)) + 'px';?
vue中需要在mounted()中进行高度初始化
获取iframe的内容
通过两个主要的API:contentWindow 和 contentDocument
iframe.contentWindow ,获取iframe的window对象 iframe.contentDocument ,获取iframe的document对象var iframe = document.getElementById("iframe1");
var iwindow = iframe.contentWindow;
var idoc = iwindow.document;
console.log("window",iwindow);?? ?//获取iframe的window对象
console.log("document",idoc);?? ?//获取iframe的document
console.log("html",idoc.documentElement);?? ?//获取iframe的html
console.log("head",idoc.head);?? ?//获取head
console.log("body",idoc.body);?? ?//获取body
通过Name属性,通过window提供的frames获取
<iframe src ="xxx.html" id="ifr1" name="ifr1" scrolling="yes">
? ? <p>Your browser does not support iframes.</p>
</iframe>
<script type="text/javascript">
? ? console.log(window.frames['ifr1'].window);
? ? console.dir(document.getElementById("ifr1").contentWindow);
</script>
window.frames['ifr1'] 返回的就是window对象,即 window.frames['ifr1']===window
同域下获取父级/子级内容
window.parent :获取上一级的window对象,如果还是iframe则是该iframe的window对象 window.top :获取最顶级容器的window对象
iframe跨域
以下形式的跨域,可以使用iframe进行解决。某一方使用iframe嵌套在另一方。
比如:http://HdhCmsTestfoo测试数据/a.html 和 http://script.foo测试数据/b.html
两个文件中分别加上 document.domain = 'foo测试数据',指定相同的主域,然后,两个文档就可以进行交互。
//b.html是以iframe的形式嵌套在a.html中
//HdhCmsTestfoo测试数据上的a.html
document.domain = 'foo测试数据';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.foo测试数据/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.foo测试数据上的b.html
document.domain = 'foo测试数据';
默认情况下 document.domain 是指 window.location.hostname 。可以手动更改,但是最多只能设置为主域名。 通常,主域名就是指不带www的hostname, 比如: foo测试数据 , baidu测试数据 。
如果,带上www或者其他的前缀,就是二级域名或者多级域名。通过上述设置,相同的domain之后,就可以进行同域的相关操作。
如果设置的iframe的域名和 top.window 的域名完全不同。则可以使用postMessage()进行通信
postMessage通信
window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
具体使用方式参考: window.postMessage
<iframe src="http://xxx测试数据" name="sendMessage"></iframe>
父页面向子页面传递信息:
// 父页面js
let ifr = window.frames['sendMessage'];
// 向子页面发送message
ifr.postmessage('give u a message', "http://xxx测试数据");
// xxx测试数据页面js
// 监听父页面传来的信息
window.addEventListener('message', receiver, false);
function receiver(e) {
? ? if (e.origin == 'http://xxx测试数据') {
? ? ? ? if (e.data == 'give u a message') {
? ? ? ? ? ? e.source.postMessage('received', e.origin); ?// 向原网页返回信息
? ? ? ? } else {
? ? ? ? ? ? alert(e.data);
? ? ? ? }
? ? }
}
在vue中使用
<iframe :src="src" ref="iframe" frameborder="0"></iframe>
1.要将获取到iframe的contentWindow属性放到mounted这个钩子函数中。
mounted() {
? ? this.iframeWin = this.$refs.iframe.contentWindow;
}
2.子页面向父页面传值
父页面代码:
// 父页面监听子页面传来的信息
mounted() {
? ? window.addEventListener('message', this.handleMessage);
? ? this.iframeWin = this.$refs.iframe.contentWindow;
},
methods: {
? ? handleMessage (event) {
? ? ? ? const data = event.data.data
? ? ? ? if(data.info === "success"){
? ? ? ? ? ? alert(data.data)
? ? ? ? }
? ? }
}
子页面代码:
sendMessage() {
? ? // 向父页面发送信息
? ? window.parent.postMessage({
? ? ? ? data: {
? ? ? ? ? ? info:"success",
? ? ? ? ? ? data:"我是子页面的test!"
? ? ? ? }
? ? }, '*');
}
3.父页面向子页面传递信息同理
sendMessage () {
? ? // 向子页面传数据,需要注意这里没有parent
? ? this.iframeWin.postMessage({
? ? ? ? info: 'success',
? ? ? ? data: "我是来自父页面的data!"
? ? }, '*')
}
注意父向子传递信息的时候,要等子页面加载完成后,再进行通信
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
查看更多关于vue中iframe使用以及结合postMessage实现跨域通信的详细内容...