如何实现 B 站多个窗口情况下同时退出&登陆?

作者站长头像
站长
· 阅读数 7

如何实现 B 站多个窗口情况下同时退出&登陆?

  1. 今天正好接到一个需求,要求网站做到类似 B 站这样,当有多个窗口时,一旦某个窗口退出,其他窗口同步退出。
  2. 我观察到的现象是,一个窗口退出以后,其他窗口会同步发送一个网络请求。

问题:其他窗口是如何监听到另一个窗口的退出动作的呢?

题主补充(2023/6/6):最后采用设置 localstorage,并且 在 app.vue 里加载下面函数,完成需求

window.addEventListener("storage",(e)=>{
if(e.key=一些判断){
//TODO:触发页面重新刷新的逻辑
}

})
回复
1个回答
avatar
test
2024-07-02

1.WebSockethtml5提供的全双工通讯的协议,浏览器和服务器之间建立一条不受限的双向通信的通道,双向数据传输,需要服务端支持。

使用方法可参考:nodejs搭建websocket服务实现多页面通信

2.StorageEvent简单有效的方式,页面A通过storage存储消息,页面B监听storage即可捕获消息。

pageA.html:

<body>
<input type="text" id="msg">
<button id="send">发送</button>
<script>
    send.onclick = function () {
        let msg = document.getElementById("msg").value
        localStorage.setItem('message', JSON.stringify({
            message: msg,
            from: 'pageA.html',
            date: Date.now()
        }))
    }
</script>
</body>

pageB.html:

<body>
收到了消息:<span id="text"></span>
<script>
    window.addEventListener('storage', function (e) {
        // console.log(e.key, e.newValue, e.oldValue)
        let msg = JSON.parse(e.newValue)
        document.getElementById('text').innerText = msg.message
    })
</script>
</body>

3.postMessage支持跨域通信,需要获取打开窗口的句柄(对象),建立联系,安全地实现跨源通信。

pageA.html:

<body>
<button id="openw">打开B页面</button>
<br>
<input type="text" id="msg">
<button id="send">发送</button>
<script>
    let newWindow = null

    openw.onclick = function () {
        console.log(333)
        newWindow = window.open('pageB.html')
    }

    send.onclick = function () {
        let msg = document.getElementById("msg").value
        if (newWindow)
            newWindow.postMessage(msg)
    }
</script>
</body>

pageB.html:

<body>
收到了消息:<span id="text"></span>
<script>
    window.addEventListener('message', function (e) {
        document.getElementById('text').innerHTML = e.data
    })
</script>
</body>
参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postM...

4.SharedWorker实现一个在浏览器后台运行的共享worker,页面通过该worker进行连接和信息的传递。同源

本地不支持,需要放到服务器。( webstorm可在浏览器中打开,vscode使用live server插件)测试。

worker.js:

let portList = [];

onconnect = function (e) {
    let port = e.ports[0];
    if (portList.indexOf(port) < 0)
        portList.push(port);
    port.onmessage = function (e) {
        boardCast(e.data);
    };
    port.start();
};

function boardCast(data) {
    portList.forEach(port => port.postMessage(data));
}

pageA.html:

<body>
<input type="text" id="msg">
<button id="send">发送</button>
<script>
    if (!!window.SharedWorker) {
        let myWorker = new SharedWorker("worker.js");

        send.onclick = function () {
            let msg = document.getElementById("msg").value
            myWorker.port.postMessage(msg);
        }

        myWorker.port.start()

    } else {
        alert("当前浏览器不支持webworker!")
    }
</script>
</body>

pageB.html:

<body>
收到了消息:<span id="text"></span>
<script>
    if (!!window.SharedWorker) {
        let myWorker = new SharedWorker("worker.js");

        myWorker.port.onmessage = function (e) {
            document.getElementById('text').innerText = e.data
        }

        myWorker.port.start()

    } else {
        alert("当前浏览器不支持webworker!")
    }
</script>
</body>
参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker

5.BroadcastChannel实现同 源 下浏览器不同窗口,Tab页,frame或者 iframe 下的 浏览器上下文 (通常是同一个网站下不同的页面)之间的简单通讯。

pageA.html:

<body>
<input type="text" id="msg">
<button id="send">发送</button>
<script>
    let channel = new BroadcastChannel('BroadcastChannel-test')
    send.onclick = function () {
        let msg = document.getElementById("msg").value
        channel.postMessage(msg)
    }
</script>
</body>

pageB.html:

<body>
收到了消息:<span id="text"></span>
<script>
    let channel = new BroadcastChannel("BroadcastChannel-test")
    channel.addEventListener("message", function (e) {
        document.getElementById('text').innerText = e.data
    })
</script>
</body>
参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Broadcast_Ch...

6.MessageChannel创建一个新的消息通道,并通过它的两个MessagePort 属性发送数据。常见场景iframe通信。

pageA.html:

<body>
<input type="text" id="msg">
<button id="send">发送</button>
<p>收到iframe消息:<span id="text"></span></p>
<iframe src="pageB.html" width='640' height='320'></iframe>
<script>
    let iframe = document.querySelector('iframe');

    send.onclick = function () {
        let channel = new MessageChannel();
        channel.port1.onmessage = onMessage
        let msg = document.getElementById("msg").value
        iframe.contentWindow.postMessage(msg, '*', [channel.port2]);
    }

    function onMessage(e) {
        document.getElementById('text').innerHTML = e.data
    }
</script>
</body>

pageB.html:

<body>
<input type="text" id="msg">
<button id="send">发送</button>
<p>收到main消息:<span id="text"></span></p>
<script>
    window.addEventListener('message', onMessage);

    let port = null

    function onMessage(e) {
        document.getElementById('text').innerHTML = e.data;
        port = e.ports[0]
    }

    send.onclick = function () {
        let msg = document.getElementById("msg").value
        if (port)
            port.postMessage(msg);
    }
</script>
</body>
参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/MessageChannel
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容