开发中我们有时会需要在当前页面中引入其他已开发的页面,直接引用其他页面或模块的功能,减少工作量,这个时候我们经常就会用到iframe。但在这种情况下我们往往还需要与嵌入的页面进行一些交互完成才能完成我们想要的功能,这个时候我们就可以用到iframe页面之间的通信来实现这种交互。
父页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>父页面</title>
</head>
<body>
<button id="btn">呼叫儿子</button>
<!-- 引用到的iframe页面,此处用本地的代替,引用线上地址与引用本地页面通信用法一致 -->
<iframe id = "son-iframe" src="./son-iframe.html" frameborder="0"></iframe>
<script>
var callSon = () => {
let msg = "儿子,听见请回答";
console.log(msg)
// 获取iframe Dom并向子iframe发送信息
document.getElementById("son-iframe").contentWindow.postMessage({
msg
}, "*")
};
// 给按钮绑定事件,点击按钮 向子iframe发送信息
document.getElementById('btn').onclick = callSon;
// 监听传进来的信息
window.addEventListener("message", (e) => {
if(e.data.msg.indexOf("父王") > -1) {
console.log("这是一块钱,拿去买小浣熊")
}
});
</script>
</body>
</html>
子页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>子页面</title>
</head>
<body>
<script>
console.log('我是son页面');
// 监听传进来的信息
window.addEventListener("message", (e) => {
if(e.data.msg.indexOf('儿子') > -1) {
console.log('收到!');
// 收到来自父iframe的消息后再向父iframe发送消息
let msg = "父王吉祥"
console.log(msg)
window.parent.postMessage({
msg
}, "*")
}
});
</script>
</body>
</html>
运行结果:
总结
1、父向子:
父iframe向子iframe通信通过获取页面中引用到的子页面iframe的Dom节点,通过其中的contentWindow获取子iframe内部window对象,并通过其中的postMessage方法进行通信。
2、子向父:
子iframe向父iframe通信通过window.parent方法获获取父iframe的window对象,并通过其中的postMessage方法进行通信。
3、postMessage方法:
// 支持接收两个参数
window.parent.postMessage("需要发送的信息,可以是对象", "目标地址,'*'代表不限地址")
4、接收到的事件对象:
// 监听传进来的信息
window.addEventListener("message", (e) => {
// 传输过来的数据在e.data当中,可以在此处对传来的数据进行一些区分,处理一些业务逻辑。
if(e.data.msg.indexOf("父王") > -1) {
console.log("这是一块钱,拿去买小浣熊")
}
});
接收到的事件对象(e)是这样的:
5、安全问题:
通过这种方式可以做一些业务逻辑处理,但不要用作重要数据传输。对于message的监听存在安全隐患。可以通过控制台直接监听到父iframe页面接收到的数据:
6、主流框架组件:
在react或vue中的使用也是同理,只需要在created(vue)或componentDidMount(react)等可拿到Dom的生命周期钩子里进行监听就可以。
7、获取数据注意:
在子iframe如果想获取父层的信息,类似于location等window对象当中的数据是不可以直接在window当中进行获取的,需要在window.parent进行获取。获取父级地址可以直接从document.referrer当中进行获取。