【前端做不了!】打开新标签页创建成功,通知其他页面更新

浏览器标签页窗口通信

本文将为你介绍窗口通信使用场景、应用、实现

一、背景

产品: 前端,你这个创建页面需要新开标签页,然后创建成功,你这个本来的页面需要更新列表。

我: 前端做不了!

私下,稍加研究,看看怎么做,然后,下面给读者看看,我是如何做的。

二、窗口通信怎么做?

首先,非常感谢自己,因为在之前很喜欢阅读很多技术文章和视频,在之前就有看过一次分析两个窗口粒子效果。当时看了当中就提到浏览器是如何通信的。

因此,所以就结合自己的需求,似乎就刚刚满足,于是有了思路以后,就开始了解相关 API ,了解以后有三种实现方式,如下:

  • BroadcastChannel
  • SharedWorker
  • localStorage/sessionStorage

这里,我就看 BroadcastChannel 这个 API ,所以接下来我会根据他来实现。

因此就可以了解到,当你需要和我一样实现相同的场景,就可以联想到这就是窗口通信。

三、利用 BroadcastChannel 实现标签页通信

BroadcastChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。 查看MDN看更多

核心使用的方法:

  • BroadcastChannel.onmessage 事件处理器,用于定义当该对象上触发了 message 事件时要执行的函数。
  • BroadcastChannel.postMessage() 向所有监听了相同频道的 BroadcastChannel 对象发送一条消息,消息内容可以是任意类型的数据。

我本人使用的是 Vue 项目开发的,考虑到各位技术栈不同这里,这里我会分别实现 Js 、Vue 、React 的三种方式

3.1 Js 实现

这里封装 createBroadcastChannel

javascript 复制代码
const createBroadcastChannel = (channelName) => {
    // 创建
    const channel = new BroadcastChannel(channelName);
	
  	// 发送
    const sendMessage = (message) => {
        channel.postMessage(message);
    };
	
    // 处理接收
    const receiveMessage = (callback) => {
        channel.onmessage = (event) => {
            callback(event.data);
        };
    };
	
    // 关闭通信
    const close = () => {
        channel.close();
    };

    return {
        channel,
        sendMessage,
        receiveMessage,
        close,
    };
};

export default createBroadcastChannel;

如何使用

在 createBroadcastChannel01.html

html 复制代码
<body>
    <button>发送</button>
    <script src="./createBroadcastChannel.js"></script>
    <script>
        const { sendMessage } = createBroadcastChannel('test_channel');

        document.querySelector('button').addEventListener('click', () => {
            sendMessage('Hello World');
        });
    </script>
</body>

在 createBroadcastChannel02.html

html 复制代码
<body>
    <script src="./createBroadcastChannel.js"></script>
    <script>
        const { receiveMessage } = createBroadcastChannel('test_channel');

        receiveMessage((event) => {
            console.log('成功接收:' + event);
        })
    </script>
</body>

当我点击发送的时候,就会获得一下结果,如图

到这里,我们就已经知道当你在使用的时候,需要在设计到通信的页面创建相同的频道,保证通信一致,这样才能保证接收到正确的数据,即 createBroadcastChannel('test_channel') 这段代码。所以通信到这里,笔者跟着实现一遍就已经掌握。

3.2 Vue 实现

Vue 我会实现一个 Vue3 + Ts 的 hook ,代码如下:

ts 复制代码
import { onBeforeUnmount, onMounted, ref, type Ref } from "vue";

export interface UseBroadcastChannelReturn<D, P> {
  channel: Ref<BroadcastChannel | undefined>;
  data: Ref<D>;
  post: (data: P) => void;
  close: () => void;
  error: Ref<Event | null>;
}

export function useBroadcastChannel<D, P>(
  channelName: string
): UseBroadcastChannelReturn<D, P> {
  const channel = ref<BroadcastChannel>();
  const data = ref<D>();
  const error = ref<Event | null>(null);

  onMounted(() => {
    try {
      channel.value = new BroadcastChannel(channelName);
      channel.value.onmessage = event => {
        data.value = event.data;
      };
    } catch (e) {
      error.value = e;
    }
  });

  onBeforeUnmount(() => {
    close();
  });

  const post = (data: P) => {
    if (channel.value) {
      channel.value.postMessage(data);
    }
  };

  const close = () => {
    if (channel.value) {
      channel.value.close();
    }
  };

  return {
    channel,
    data,
    post,
    close,
    error
  };
}

3.3 React 实现

我会实现React个 React + Ts 的 hook ,代码如下:

ts 复制代码
import React, { useEffect, useRef, useState } from 'react';

export interface UseBroadcastChannelReturn<D, P> {
 channel: BroadcastChannel | undefined;
 data: D | undefined;
 post: (data: P) => void;
 close: () => void;
 error: Event | null;
}

export function useBroadcastChannel<D, P>(
 channelName: string
): UseBroadcastChannelReturn<D, P> {
 const [channel, setChannel] = useState<BroadcastChannel | undefined>();
 const [data, setData] = useState<D>();
 const [error, setError] = useState<Event | null>(null);
 const channelRef = useRef<BroadcastChannel>();

 useEffect(() => {
   try {
     const newChannel = new BroadcastChannel(channelName);
     newChannel.onmessage = (event) => {
       setData(event.data);
     };
     channelRef.current = newChannel;
     setChannel(newChannel);
   } catch (e) {
     setError(e);
   }
   
   return () => {
     close();
   };
 }, [channelName]);

 const post = (dataToSend: P) => {
   if (channelRef.current) {
     channelRef.current.postMessage(dataToSend);
   }
 };

 const close = () => {
   if (channelRef.current) {
     channelRef.current.close();
   }
 };

 return {
   channel,
   data,
   post,
   close,
   error
 };
}

不管是 Vue 还是 React 使用方式都参考 Js 的方式,返回了 channel 是方便使用更多的 API

四、总结

到这里就结束了,我们讨论了窗口通信是怎么做的。以及在什么场景下会使用到。BroadcastChannel 是一个非常强大的API,帮助我实现了标签页的通信。希望这篇文章能帮助到你,就像我曾经也被其他笔者帮助一样,我只是将这份热爱传递下去,感谢您阅读到最后,下期再见。

相关推荐
火山引擎开发者社区1 分钟前
构建专属的飞书群开发助手,AgentKit Studio 一键部署 DeepSeek Harness Super-Agent
前端
啾咪orJIUMI2 小时前
Vue 3 + 高德地图封装实战:点位、区域、Loca 流光与 Vue 信息窗体
前端·vue.js
掘金者阿豪2 小时前
AI数据库不只是向量检索:从数据语义到库内智能计算的技术演进
前端
梦里寻码2 小时前
我用 NestJS + Vue3 写了一套完整的研发管理系统(58 表 / 229 API / 130 项断言,全开源
前端·后端·算法
FRing032 小时前
vue2干货总结8(路由模块封装、router-link、声明式导航、路由重定向、编程式导航)
开发语言·前端·vue.js·vue2
SameX2 小时前
HarmonyOS ArkUI Dialog 复用 用 @CustomDialog + enum type 做多类型统一管理的做法
前端
AiMan3 小时前
豆包爱学还是不可以导出左侧所有对话,只能单容导出,方法不对吗
前端
无懈可击3 小时前
Vue 可视化AI表单设计器 FcDesigner v3.6 版本发布,支持导出 SQL功能!
vue.js·开源·ai编程
AiMan3 小时前
Grok生成的内容能否下载吗?
前端
徐小夕4 小时前
JitArchives,一款基于JitWord协同AI文档打造的企业级电子档案系统
前端·vue.js·github