平時(shí)工作中有時(shí)會(huì)遇到頁(yè)面嵌套的情況灾梦,一般是用iframe解決野舶。那么妇垢,兩個(gè)頁(yè)面如何通信呢巾遭?下面分兩種情況進(jìn)行:
一肉康、父子頁(yè)面同源的情況
現(xiàn)在有兩個(gè)不同源的iframe嵌套頁(yè)面,父頁(yè)面parent.html
,子頁(yè)面child.html
灼舍,二者代碼如下:
// parent.html
// ...
<iframe
id='testIframe'
name='test'
src='./child.html'
frameborder='0'
scrolling='no'>
</iframe>
<script type="text/javascript">
function parentConsole(data) {
console.log(data)
}
</script>
// ...
// child.html
// ...
<script type="text/javascript">
function childConsole(data) {
console.log(data)
}
</script>
// ...
1. 父頁(yè)面調(diào)用子頁(yè)面方法
可以通過(guò)iframe的id或者name屬性拿到iframe的window對(duì)象吼和,然后直接調(diào)用子頁(yè)面方法即可。我們把需要發(fā)送給子頁(yè)面的信息放到方法childConsole
里。如下:
var iframeDom = document.getElementById('testIframe');
// 需要等iframe加載完成后執(zhí)行,不然有可能會(huì)報(bào)錯(cuò)
iframeDom.onload = function () {
var data = 'hello, child!';
iframeDom.contentWindow.childConsole(data);
}
或
var iframeDom = document.getElementById('testIframe');
iframeDom.onload = function () {
var data = 'hello, child!';
test.window.childConsole(data);
}
2. 子頁(yè)面調(diào)用父頁(yè)面方法
可以通過(guò)window.top或者window.parent拿到父頁(yè)面的window對(duì)象吐绵。然后直接調(diào)用父頁(yè)面的方法即可弓柱。同樣,把需要發(fā)給父頁(yè)面的信息放到方法parentConsole
里。如下:
var data = 'hello, parent!';
window.top.parentConsole(data); // 或者使用window.parent.parentConsole(data)也行
二、父子頁(yè)面跨域的情況
可以通過(guò)postMessage
來(lái)實(shí)現(xiàn)通信。
otherWindow.postMessage(message, targetOrigin, [transfer]);
其中的參數(shù):
otherWindow
目標(biāo)窗口塔粒。比如 iframe 的 contentWindow 屬性
message
將要發(fā)送到其他 窗口 的數(shù)據(jù)。
targetOrigin
目標(biāo)窗口的域筐摘。其值可以是字符串"*"(表示無(wú)限制)或者一個(gè) URI卒茬。不提供確切的 targetOrigin 將導(dǎo)致數(shù)據(jù)泄露到任何對(duì)數(shù)據(jù)感興趣的惡意站點(diǎn)。
現(xiàn)在有兩個(gè)不同源的iframe嵌套頁(yè)面咖熟,父頁(yè)面http://127.0.0.1:8001/parent.html,子頁(yè)面http://127.0.0.1:8002/child.html(本地分別對(duì)兩個(gè)html起了兩個(gè)服務(wù))圃酵,其中父頁(yè)面嵌套部分代碼如下:
// http://127.0.0.1:8001/parent.html
<iframe
id='testIframe'
name='test'
src='http://127.0.0.1:8002/child.html'
frameborder='0'
scrolling='no'>
</iframe>
1. 父頁(yè)面發(fā)送信息,子頁(yè)面接收信息
// http://127.0.0.1:8001/parent.html
// 父頁(yè)面發(fā)送信息
document.getElementById('testIframe').onload = function () {
test.window.postMessage('hello, child!', 'http://127.0.0.1:8002');
}
// http://127.0.0.1:8002/child.html
// 子頁(yè)面接收信息
window.addEventListener('message', e => {
// 通過(guò)origin對(duì)消息進(jìn)行過(guò)濾馍管,避免遭到XSS攻擊
if (e.origin === 'http://127.0.0.1:8001') {
console.log(e.origin) // 父頁(yè)面所在的域
console.log(e.data) // 父頁(yè)面發(fā)送的消息, hello, child!
}
}, false);
2. 子頁(yè)面發(fā)送信息郭赐,父頁(yè)面接收信息
// http://127.0.0.1:8002/child.html
window.top.postMessage('hello, parent!', 'http://127.0.0.1:8001');
// http://127.0.0.1:8001/parent.html
window.addEventListener('message', e => {
// 通過(guò)origin對(duì)消息進(jìn)行過(guò)濾,避免遭到XSS攻擊
if (e.origin === 'http://127.0.0.1:8002') {
console.log(e.origin) // 子頁(yè)面所在的域
console.log(e.data) // 子頁(yè)面發(fā)送的消息, hello, parent!
}
}, false);
通過(guò)postMessage
和window.addEventListener('message', e => { ... })
配合使用确沸,我們就能夠完成跨域iframe父子頁(yè)面的通信捌锭。
當(dāng)然對(duì)于同源的iframe父子頁(yè)面也可以采用postMessage
的方式來(lái)發(fā)送接收信息。
參考資料:
postMessage API:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
iframe跨域通信(postMessage):https://juejin.cn/post/6844904120680185869