纯前端怎么实现不同标签页下的数据通信

前言

我记得之前有做过这样的一个需求——可以简化的看作为一个 TODO List ,我打开了两个 tab 页,都是对应这个 TODO List

然后我在 A 页面新增一个,不出意外的话,在 B 页面是看不到的。产品当时跟我提了一下这个,让测试给我提了个 Bug

我那个时候下意识的反应就是找后端接一下 WebSocket ,但接一个 WebSocket 谈何简单,单单是公司网关那里分分钟让你搞一天都搞不定。

我就接着搜了一下,看看有没有纯前端的实现方案,还真让我找到了。今天我们就一起讨论下:纯前端如何实现不同标签页下的数据通信。

TODO List Demo

这里我为了演示,做了一个最简版本的 TODO List ,大家知道意思就行:

import { Button, Input, Row } from "antd";
import { useState } from "react";

const Todo = () => {
  const [list, setList] = useState([]);
  const [value, setValue] = useState("");
  const handleCreate = () => {
    if (!value) {
      return;
    }
    const arr = [...list];
    arr.push(value);
    setList(arr);
    setValue("");
  };
  return (
    <div style={{ margin: 20 }}>
      <Row>
        <Input
          value={value}
          onInput={(e) => setValue(e.target.value)}
          style={{ width: 200, marginRight: 16 }}
          placeholder="输入点什么"
        />
        <Button onClick={handleCreate} type="primary">
          增加
        </Button>
      </Row>
      <ul>
        {list.map((item) => {
          return <li>{item}</li>;
        })}
      </ul>
    </div>
  );
};

export default Todo;

image.png

代码很简单,仅为了后续演示数据同步使用。就是用一个输入框加一个确认按钮,然后把输入的东西 push 到数组里面,把这个数组渲染出来。

localStorage

localStorage 相信各位前端同学都不会陌生,数据存储在 localStorage 中是持久的,即使用户关闭了浏览器窗口,数据也会保留下来,直到用户手动清除或者被JS脚本清除。

在同源的情况下,localStorage存储的数据是共享的,也就是说假设我打开了两个同源的标签页 AB ,我在 A 中写入了 localStorage ,在 B 标签页是可以获取到的。

且我们是可以监听 localStorage 的变化的,既然数据能共享,取到的是同一份。而且还能监听数据的变化,这不就可以实现数据通信同步了吗?

首先,在 list 变化的时候写入 localStorage

useEffect(() => {
    window.localStorage.setItem(CACHE_KEY, JSON.stringify(list));
}, [list]);

然后在 localStorage 变更的时候更新 state 。注意:localStorage 的变化事件 (storage 事件) 在其他标签页或窗口修改 localStorage 时才会触发。

  const handleStorageChange = useCallback(
    (event) => {
      const { key, newValue } = event;
      if (isEmpty(newValue)) {
        setList([]);
      }
      if (key === CACHE_KEY) {
        if (isEmpty(newValue)) {
          setList([]);
        } else if (JSON.stringify(list) !== newValue) {
          setList(JSON.parse(newValue));
        }
      }
    },
    [list]
  );

  useEffect(() => {
    window.addEventListener("storage", handleStorageChange);
    return () => {
      window.removeEventListener("storage", handleStorageChange);
    };
  }, [handleStorageChange]);

所以为了验证这个功能,我们可以打开两个标签页来看看效果:

Kapture 2024-05-04 at 21.52.47.gif

可以看到,在 A 标签页输入的东西可以顺利同步到 B 标签页中,也是实现了纯前端下的数据通信。

但可能有人觉得,本身我这个功能不需要依赖 localStorage ,搞得我现在又需要在本地存储再存一份。有没有不依赖本地存储的跨标签页数据通信方式呢?

Broadcast Channel API

答案是有的,那就是——Broadcast Channel API,我们可以一起来看看 MDN 对它的解释:

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

也就是说这个 API 设计出来就是为了让我们对同源的不同窗口做数据通信的。

看一下兼容性:

image.png

除了 IE 不支持,其他大多数主流浏览器都支持。

整体的 API 用起来十分简单,我们一起来看看。

首先刚开始需要加入或者创建一个频道,跟我们使用 ws 的时候一样,需要创建或者加入一个房间,组件销毁时退出频道。

  useEffect(() => {
    const bc = new BroadcastChannel(CHANNEL_NAME);
    channel.current = bc;
    channel.current.onmessage = function (ev) {
      if (ev?.data?.type === "add") {
        const arr = [...list];
        arr.push(ev.data.value);
        setList(arr);
      }
    };
    return () => {
      channel.current && channel.current.close();
    };
  }, [list]);

onmessage 中就可以接收到频道中其他标签页发送过来的消息,在这里获取到消息之后更新 state 。同样的,在新增数据的时候,通过频道发送消息。

  const handleCreate = () => {
    if (!value) {
      return;
    }
    const arr = [...list];
    arr.push(value);
    setList(arr);
    setValue("");
    channel.current.postMessage({
      type: "add",
      value,
    });
  };

一样也是可以实现跨标签页的数据通信的。

Kapture 2024-05-04 at 21.52.47.gif

最后

以上就是本文的全部内容,主要介绍了两种纯前端实现不同标签页下的数据通信的方式,如果你觉得有意思的话,点点关注点点赞吧~

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端面和控制层之间进行数据交换,通常使用以下几种方式: 1. 表单提交:通过表单的提交,将用户在前端面输入的数据发送到控制层。在前端面中,可以使用`<form>`标签来创建表单,并使用`<input>`、`<select>`、`<textarea>`等标签来收集用户输入的数据。在控制层,可以通过接收表单数据的方式来获取前端面传递过来的数据。 2. AJAX:使用AJAX(Asynchronous JavaScript and XML)技术,可以通过异步请求向控制层发送数据,并接收控制层返回的数据。在前端面中,可以使用JavaScript通过XMLHttpRequest或Fetch API等方式发送请求,并处理返回的数据。在控制层,可以接收并处理前端发送的请求,并返回相应的数据。 3. RESTful API:通过使用RESTful风格的API,前端面可以通过HTTP请求向控制层发送数据,并获取控制层返回的数据。在前端面中,可以使用JavaScript的Fetch API或第三方库(如Axios)发送HTTP请求,并处理返回的数据。在控制层,可以根据请求的方法(GET、POST、PUT、DELETE等)和URL路径来处理请求,并返回相应的数据。 4. WebSocket:WebSocket是一种双向通信协议,可以实现前端面和控制层之间的实时数据交换。在前端面中,可以使用JavaScript的WebSocket API与后端建立WebSocket连接,并发送和接收数据。在控制层,可以接收前端面发送的数据,并向前端面推送数据。 这些方式可以根据具体的需求和技术栈来选择和使用。同时,还可以结合各种框架和库(如Spring MVC、Express.js、Vue.js、React等)来简化数据交换的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值