需求背景
最近在做H5項目時,遇到一個需求,公司所有的項目共用了一個防人機頁面,當人機驗證完成時需要把結果參數發送給調用它的父頁面,APP端在使用驗證頁面時,結果是通過H5與APP互動方法傳遞的;但是H5引用這個頁面時,隻能通過iframe内嵌的方式來實作,這樣在驗證通過後就面臨着iframe内嵌頁面需要将驗證結果發送給外部父頁面,通知外部父頁面做相應的處理;
實作方式
1.父頁面發送消息,子頁面接受消息
父頁面:
<!-- a.index.html -->
<h1>父頁面</h1>
<iframe id="iframe" src="http://b.index.com"></iframe>
const iFrame = document.getElementById('iframe')
<!-- 需要等到iframe中的子頁面加載完成後才發送消息,否則子頁面接收不到消息 -->
iFrame.onload = function(){
<!-- iFrame.contentWindow擷取到iframe的window對象 -->
iFrame.contentWindow.postMessage('父頁面發送的消息','http://b.index.com');
}
子頁面:
//有發送就有接收,與postMessage配套使用的就是message事件
window.addEventListener('message',e=>{
<!-- 對消息來源origin做一下過濾,避免接收到非法域名的消息導緻的xss攻擊 -->
if(e.origin==='http://a.index.com'){
console.log(e.origin) //父頁面URL,這裡是http://a.index.com
console.log(e.source) // 父頁面window對象,全等于window.parent/window.top
console.log(e.data) //父頁面發送的消息
}
},false)
2.子頁面發送消息,父頁面接受消息
子頁面:
window.parent.postMessage('子頁面發送的消息','http://a.index.com')
父頁面:
window.addEventListener('message',e=>{
<!-- 對消息來源origin做一下過濾,避免接收到非法域名的消息導緻的xss攻擊 -->
if(e.origin==='http://b.index.com'){
console.log(e.origin) //子頁面URL,這裡是http://b.index.com
console.log(e.source) // 子頁面window對象,全等于iframe.contentWindow
console.log(e.data) //子頁面發送的消息
}
},false)
注意:
- window.postMessage中的window指的是你想發送跨域消息的那個視窗(你需要通信的目标視窗),而不是自身視窗的window
- 父頁面中:父頁面向子頁面發送跨域資訊,window就是在父頁面中嵌入的iframe指向的子頁面的window,即:iFrame.contentWindow
- 子頁面中:子頁面想父頁面發送跨域資訊,window就是父頁面的window,在這裡因為子頁面是嵌入到父頁面中的,對于子頁面來講,window就是top或者parent
- 需要等到iframe中的子頁面加載完成後才發送消息,否則子頁面接收不到消息
- 在監聽message事件時需要判斷一下消息來源origin
最後附送父頁面檢測到子頁面發送的消息後,調用iframe子頁面自重新整理方法:
父頁面:
window.addEventListener("message", e => {
if (e.data && e.data.verifData) {
//調用子頁面自重新整理
e.source.location.reload(true)
}
}, false)