天天看點

前端跨浏覽器标簽頁資料共享解決方案

作者:秘密菜單

需求描述

vue 項目中有一個工單消息通知清單頁,每條消息有已讀和未讀狀态,點選消息會用 window.open 打開一個新的浏覽器标簽頁跳轉到工單清單頁,工單清單頁裡有項操作是檢視消息,會彈窗顯示出具體的詳細内容,進入這個彈窗就代表使用者已經看到消息了,此時會去調後端接口修改消息狀态為已讀。

需要實作使用者已讀目前消息後,前面一個工單消息通知清單頁的已讀/未讀狀态同步更新。

想到的實作方式

  • 1、直接用定時器 setInterval 不斷地輪詢調後端接口查最新狀态
  • 2、用 vuex 實作全局狀态共享
  • 3、用 localStorage 實作資料共享

第1種最簡單,不過有點 low 直接 pass 掉了。第2種乍一看好像可以實作,實際上你去試一下就會發現問題,vuex 是不能跨标簽頁共享的,每一個标簽頁下的 vuex 執行個體是獨立的,你修改了目前标簽頁下的 vuex 裡資料,其他标簽頁是不受影響的,網上找到一個插件 vuex-shared-mutations,不過看了下最近維護還是4年以前,是以也直接 pass 了。

最後用第3種實作了,自己在 localStorage 裡存一個辨別,然後在需要同步資料的頁面開一個 storage 的事件監聽,去監聽本地緩存的變化,如果是目标值發生變化,直接重新擷取資料更新就可以了,具體的 demo 代碼:

消息通知清單頁

<template>
    <div>
        <p v-for="(item, index) in noticeList" :key="index">消息{{ index + 1 }}:{{ item.title }}</p>
    </div>
</template>
<script>
export default {
    data() {
        return {
            noticeList: [
                { title: '我是第一條消息' },
                { title: '我是第二條消息' },
            ]
        }
    },
    created() {
        // 跨标簽頁監聽
        window.addEventListener('storage', this.storageChange)
    },
    beforeDestroy() {
        window.removeEventListener('storage', this.storageChange)
    },
    methods: {
        storageChange(e) {
            if (e && e.key == 'targetKey' && e.newValue) {
                // 在這裡更新資料
            }
        },
    }
}
</script>           

工單清單頁

<template>
    <div>
        <p @click="handleRead">讀消息</p>
    </div>
</template>
<script>
export default {
    data() {
        return {}
    },
    methods: {
        handleRead() {
            localStorage.setItem('targetKey', 1)
        },
    }
}
</script>           

效果是實作了,最終感覺還是不太滿意,在群裡詢問了一圈,果然有新發現,postMessage 和 BroadcastChannel 這兩個浏覽器的新 api 是可以實作跨标簽頁通信的,postMessage 還可以實作跨源通信,一般用在和 iframe 通信比較多。

終極版

最終嘗試了 BroadcastChannel 版本:

接收消息:

const BC = new BroadcastChannel('notice')
BC.onmessage = (e) => {
    console.log('消息來了:', e)
}

// 斷開連接配接
// BC.close()           

發送消息:

const BC = new BroadcastChannel('notice')
BC.postMessage('發出消息,趕緊去更新資料吧')

// 斷開連接配接
// BC.close()           

相關文檔

  • BroadcastChannel
  • postMessage

繼續閱讀