同源頁(yè)面
廣播模式,頁(yè)面將消息通知給一個(gè)中轉(zhuǎn),中轉(zhuǎn)再通知給各個(gè)頁(yè)面。中轉(zhuǎn)可以是一個(gè) BroadCast Channel 實(shí)例、一個(gè) Service Worker 或是 LocalStorage。
BrocastChannel
BrocastChannel可以實(shí)現(xiàn)同源下瀏覽器不同窗口,tab頁(yè),frame或frame下的瀏覽器上下文之間的通信。
// a頁(yè)面
var bc = new BroadcastChannel('qwer')
bc.postMessage('發(fā)送數(shù)據(jù)')
// b頁(yè)面
var bc = new BroadcastChannel('qwer')
bc.onmessage = function(e) {
console.log(e)
}
/** 消息發(fā)送后,所有連接到該頻道的 BrocastChannel對(duì)象上都會(huì)觸發(fā) meaasge事件,
該事件沒有默認(rèn)行為,可以使用`onmessage`事件處理程序來定義一個(gè)函數(shù)處理消息
**/
LocalStorage
LocalStorage是前端常用的本地存儲(chǔ),當(dāng)LocalStorage變化是,會(huì)觸發(fā)storage事件,發(fā)送消息時(shí),將消息寫入LocalStorage中,然后在各個(gè)頁(yè)面中,通過監(jiān)聽storage事件即可收到通知。
// a頁(yè)面
window.addEventListener('storage', function(e) {
console.log(e)
})
// b頁(yè)面
localStorage.setItem('qwer', 10000)
Service Worker
Service Worker與頁(yè)面通信
前端跨頁(yè)面通信的方法
共享存儲(chǔ) + 長(zhǎng)輪詢模式
SharedWorker
SharedWorker可以開啟后臺(tái)線程運(yùn)行腳本,并且多個(gè)頁(yè)面之間可以共享,通過port.postMessage發(fā)送消息,通過監(jiān)聽message
事件實(shí)現(xiàn)。如果a頁(yè)面向后臺(tái)線程發(fā)送消息,后臺(tái)線程觸發(fā)message
事件后再發(fā)送的消息只能被a頁(yè)面接收,即SharedWorker可以一個(gè)線程處理不同的頁(yè)面邏輯,然后將結(jié)果返回對(duì)應(yīng)的頁(yè)面。
- 根據(jù)以上原理,在SharedWorker腳本中設(shè)置共享數(shù)據(jù)以實(shí)現(xiàn)頁(yè)面間的通信
//可以在chrome://inspect中對(duì)子線程中的代碼進(jìn)行調(diào)試
onconnect = function(e) {
console.log(e)
const port = e.ports[0]
port.onmessage = function(event){
console.log(event)
port.postMessage(event.data)
}
}
頁(yè)面1中的代碼
var sharedWorker = new SharedWorker('./shareWorker.js', 'cpc')
sharedWorker.port.postMessage({
a: 1,
b: 2
})
// 發(fā)送數(shù)據(jù),此時(shí)共享數(shù)據(jù)的值已經(jīng)被更改
頁(yè)面2中的代碼
var sharedWorker = new SharedWorker('./shareWorker.js', 'cpc')
sharedWorker.port.postMessage({ get: true })
// 如果需要實(shí)時(shí)更新的話,可能需要`setInterval`進(jìn)行輪詢
indexDB方案
非同源頁(yè)面
非同源頁(yè)面之間的通信通過iframe
實(shí)現(xiàn)。各個(gè)需要通信的頁(yè)面加載應(yīng)該相同的iframe
,這些iframe
之間使用的是同一個(gè)url
,屬于同源,可以相互通信,接收到消息后postMessage
到主頁(yè)面即可。
// iframe中的代碼
const bc = new BroadcastChannel('cpc')
window.addEventListener('message', function(e) {
console.log(e)
if(e.origin === 'https://magazine.heytapimage.com' || e.origin === 'https://magazine-static-cpc.heytapimage.com') {
bc.postMessage(e.data)
console.log('bc postMessage')
}
})
bc.onmessage = function(e) {
window.parent.postMessage(e.data, 'https://magazine.heytapimage.com') // 支持傳入指定域名或*
console.log('bc receiveMessage')
}
a頁(yè)面的代碼
<iframe src="https://dhfs-test-cpc.wanyol.com/iframe.html"></iframe>
<script>
window.frames[0].window.postMessage({
atob: true,
numb: 11,
desc: 'a頁(yè)面向b頁(yè)面發(fā)送的數(shù)據(jù)'
}, 'https://dhfs-test-cpc.wanyol.com');
</script>
b頁(yè)面的代碼
<iframe src="https://dhfs-test-cpc.wanyol.com/iframe.html"></iframe>
<script>
window.addEventListener('message', function (e) {
console.log('b頁(yè)面接收到數(shù)據(jù)')
if(e.data.atob) {
console.log(e.data)
}
});
</script>