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

浏览器标签页窗口通信

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

一、背景

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

我: 前端做不了!

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

二、窗口通信怎么做?

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

因此,所以就结合自己的需求,似乎就刚刚满足,于是有了思路以后,就开始了解相关 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 项目开发的,考虑到各位技术栈不同这里,这里我会分别实现 JsVueReact 的三种方式

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 实现

我会实现ReactReact + 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,帮助我实现了标签页的通信。希望这篇文章能帮助到你,就像我曾经也被其他笔者帮助一样,我只是将这份热爱传递下去,感谢您阅读到最后,下期再见。

相关推荐
Jiaberrr1 分钟前
Vite环境下uniapp Vue 3项目添加和使用环境变量的完整指南
前端·javascript·vue.js·uni-app
Marry1.010 分钟前
uniapp背景图用本地图片
前端·uni-app
夏河始溢15 分钟前
一七八、Node.js PM2使用介绍
前端·javascript·node.js·pm2
记忆深处的声音16 分钟前
vue2 + Element-ui 二次封装 Table 组件,打造通用业务表格
前端·vue.js·代码规范
陈随易17 分钟前
兔小巢收费引发的论坛调研Node和Deno有感
前端·后端·程序员
熊的猫31 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn38 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
四喜花露水1 小时前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie2 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript