跨页面通信

同源

BroadcastChannel

在相同的源的浏览器上下文(windows,tabs,frames或者iframes)之间进行简单的通信

API

  • 事件监听:
  1. (on)message: 监听到有数据发送时触发;
  2. (on)onmessageerror: 监听到消息错误是触发;
  • 方法:
  1. postMessage(msg: any): 发送消息;
  2. close(): 关闭channel,不再接收;

发送页:

// pages/dispather.js
import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useState } from 'react';

export default function Dispather() {
  const [message, setMessage] = useState('');

  // 发送消息
  const handleSendMessage = () => {
    // new BroadcastChannel的参数发送方和接收方必须是一样的
    const channel = new BroadcastChannel('this_params_must_be_same');
    channel.postMessage(message);
  };
  return (
    <div className={styles.container}>
      <Head>
        <title>Dispatcher</title>
      </Head>

      <main className={styles.main}>
        <h4>This is messege to be sent:</h4>
        <input
          value={message}
          onChange={e => {
            setMessage(e.target.value);
          }}
        />
        <br />
        <button onClick={handleSendMessage}>click to send</button>
      </main>
    </div>
  );
}

复制代码

接收页

// pages/receiver.js
import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useEffect, useState } from 'react';

export default function Receiver() {
  // --监听消息接收--
  const handleListenMessage = () => {
    // new BroadcastChannel的参数发送方和接收方必须是一样的
    const channel = new BroadcastChannel('this_params_must_be_same');
    console.log('This channel is working:', channel.name, '(channel.name)');
    channel.onmessage = function (event) {
      setMessage(event.data);
    };
  };
  const [message, setMessage] = useState('');

  // handleListenMessage不能直接在组件里执行,因为用的ssr,在server端没有BroadcastChannel这个API
  useEffect(() => {
    handleListenMessage();
  }, []);
  // ReferenceError: BroadcastChannel is not defined
  // handleListenMessage();
  return (
    <div className={styles.container}>
      <Head>
        <title>Receiver</title>
      </Head>

      <main className={styles.main}>
        <h4>This is messege received:</h4>
        <h4>{message}</h4>
        <br />
      </main>
    </div>
  );
}

复制代码

Shared Worker

普通的 Worker 之间独立运行、数据互不相通;而多个 Tab 注册的 Shared Worker 则可以实现数据共享。

import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useState, useEffect } from 'react';

export default function Dispather() {
  const [message, setMessage] = useState('');
  const [worker, setWorker] = useState('');
  useEffect(() => {
    // new SharedWorker引用同一个脚本,名字必须要一样才能数据共享
    setWorker(new SharedWorker('/worker.js', 'this_name_must_be_same'));
  }, []);

  // 发送消息
  const handleSendMessage = () => {
    worker.port.postMessage(message);
  };
  return (
    <div className={styles.container}>
      <Head>
        <title>Dispatcher</title>
      </Head>

      <main className={styles.main}>
        <h4>This is messege to be sent:</h4>
        <input
          value={message}
          onChange={e => {
            setMessage(e.target.value);
          }}
        />
        <br />
        <button onClick={handleSendMessage}>click to send</button>
      </main>
    </div>
  );
}

复制代码

接收页

import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useEffect, useState } from 'react';

export default function Receiver() {
  const [worker, setWorker] = useState('');
  useEffect(() => {
    setWorker(new SharedWorker('/worker.js', 'this_name_must_be_same'));
    handleListenMessage();
  }, []);
  // --监听消息接收--
  const handleListenMessage = () => {
    // new SharedWorker引用同一个worker
    console.log('This worker is working:', worker);
    if (worker.port) {
      worker.port.onmessage = function (event) {
        setMessage(event.data);
      };
    }
  };
  const [message, setMessage] = useState('');

  return (
    <div className={styles.container}>
      <Head>
        <title>Receiver</title>
      </Head>

      <main className={styles.main}>
        <h4>This is messege received:</h4>
        <h4>{message}</h4>
        <br />
      </main>
    </div>
  );
}
复制代码

worker

// public/worker.js
// worker.js
const ports = new Set();
// 链接时触发
self.onconnect = event => {
  // 通过 event.ports 拿到 父线程MessageEvent,new SharedWorker时第二个参数想通被认为是同一个port
  const port = event.ports[0];
  console.log(
    '子线程worker的connect事件在父线程port的new SharedWorker时候触发,此时的port是:',
    event.ports[0],
    '一共的父线程port有:',
    ports
  );

  ports.add(port);

  port.onmessage = e => {
    // port.onmessage 监听父线程的消息
    console.log(e.data);
    console.log(
      '父线程port的message事件在postMessage时候触发,此时的port是:',
      port,
      'message是:',
      e.data,
      '一共的父线程port有:',
      ports,
      '排除自己还有',
      Array.from(ports).filter(p => p !== port)
    );
    Array.from(ports)
      .filter(p => p !== port) // 广播消息时把自己除掉
      .forEach(p => p.postMessage(e.data)); // 向链接池里的用户发送消息
  };
};
复制代码

LocalStorage

同源限制

一个源共享同一个 localStorage,a.meituan.com 和 b.meituan.com 是两个域名,不能共享storage;但同源不同tab页可以共享localStorage

大小限制

localStorage的最大限制是5MB,如果存满了,再往里存东西,或者要存的东西超过了剩余容量,会存不进去并报错(QuotaExceededError)

API

  1. 发送window.localStorage.setItem('localStore', JSON.stringify(message));

  2. 接收window.onstorage = function (e) {if (e.key === 'localStore')const data = JSON.parse(e.newValue);};

import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useState, useEffect } from 'react';

export default function Dispather() {
  const [message, setMessage] = useState('');

  // 发送消息
  const handleSendMessage = () => {
    window.localStorage.setItem('localStore', JSON.stringify(message));
  };
  return (
    <div className={styles.container}>
      <Head>
        <title>Dispatcher</title>
      </Head>

      <main className={styles.main}>
        <h4>This is messege to be sent:</h4>
        <input
          value={message}
          onChange={e => {
            setMessage(e.target.value);
          }}
        />
        <br />
        <button onClick={handleSendMessage}>click to send</button>
      </main>
    </div>
  );
}
复制代码
import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useEffect, useState } from 'react';

export default function Receiver() {
  useEffect(() => {
    handleListenMessage();
  }, []);
  // --监听消息接收--
  const handleListenMessage = () => {
    window.onstorage = function (e) {
      console.log(e);
      if (e.key === 'localStore') {
        const data = JSON.parse(e.newValue);
        setMessage(data);
      }
    };
  };
  const [message, setMessage] = useState('');

  return (
    <div className={styles.container}>
      <Head>
        <title>Receiver</title>
      </Head>

      <main className={styles.main}>
        <h4>This is messege received:</h4>
        <h4>{message}</h4>
        <br />
      </main>
    </div>
  );
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享