最近有个需求是在父页面打开一个弹窗,然后弹窗里面是一个iframe,在关闭弹窗时需要把iframe中的audio标签的音频链接清空和做一些其他的操作。因为以前很少接触iframe,所以对它有点陌生,在经过大佬的指点和上网查阅后找到了解决方法,于是打算写一篇博客记录下iframe之间的通讯。
先说下我那个需求的解决方案,我在父页面的关闭弹窗事件中调用window.postMessage()把关闭窗口的信息传到iframe,iframe接收到这个信息后就把音频的url重置掉。
// 父页面
detailCancel = () => {
// 关闭弹窗时通知iframe把当前音频的url清空
// 首先获取iframe节点,然后
let iframe = document.querySelector('#iframe')
iframe.contentWindow.postMessage('close', "*")
this.setState({
detail_visible: false,
});
};
// 子页面(iframe)
componentDidMount() {
// 在didmount生命周期注册message的监听事件,当获取到关闭的信息时执行需要的操作
window.addEventListener('message', (e) => {
//接收到父页面传过来的关闭信息后把音频的url清空
if (e.data === 'close') {
this.setState({
audioUrl: ''
})
}
})
}
然后说一下iframe父子通讯的另一种方式,上面提到的这个方法可以适用于父子页面不同域的情况,还有一种方法是同域间的父子通讯。
1、父传子同域通讯
父页面可以通过iframe的id或者name属性直接访问到子iframe的window对象
// 父页面
detailCancel = () => {
let iframe = document.querySelector('#iframe')
// 这里改为了在父页面直接调用子iframe页面的resetAudioUrl()方法
iframe.window.resetAudioUrl()
this.setState({
detail_visible: false,
});
};
// 子页面(iframe)
resetAudioUrl = () => {
this.setState({
audioUrl: "",
})
}
因为在这种情况我们是直接调用子iframe页面的方法,如果在调用时子iframe页面还没有加载完成的话时会导致页面报错的,所以上面的代码还需要在父页面的detailCancel()方法这里加一个判断此时的子页面是否加载完成了。
判断iframe是否加载完成有两种方法:
a、iframe.document.readyState == "complete"来判断
b、iframe.onload = function() {} 使用onload回调函数,把调用子iframe的执行语句放到onload的回调函数里面即可
// 父页面(优化后)
detailCancel = () => {
let iframe = document.querySelector('#iframe')
// 这里改为了在父页面直接调用子iframe页面的resetAudioUrl()方法
// 调用之前先判断子iframe是否加载完成了
iframe.document.readyState == "complete" && iframe.window.resetAudioUrl()
this.setState({
detail_visible: false,
});
};
// 子页面(iframe)
resetAudioUrl = () => {
this.setState({
audioUrl: "",
})
}
2、子传父同源通讯
直接使用window.parent.要调用的父页面的方法就可以了