进阶篇:Web 跨页面通信

Web 跨页面通信,指浏览器中不同浏览上下文之间的数据传递,包含:Tab 标签页、独立窗口、iframe 内嵌页面、新开弹窗等。

根据浏览器同源策略,可严格分为两大类场景:

  • 同源跨页面通信:协议、域名、端口完全一致。
  • 非同源跨页面通信:跨域通信,受浏览器安全策略限制。

同源跨页面通信方案

以下所有方案仅支持同源页面通信,无法跨域,是多 Tab、多窗口、iframe 同源数据同步的核心方案。

BroadcastChannel(广播通道)

核心原理:浏览器原生提供的同源全局命名广播通道。只要多个页面、Tab、iframe 使用完全相同的频道名称,即可加入同一个广播域,实现全员消息广播、全员监听。

关键特性:原生零依赖、专门用于多上下文广播、频道隔离、支持任意数据类型。

const bc = new BroadcastChannel('app-channel');

bc.onmessage = (e) => {
  console.log('收到广播消息:', e.data);
};

bc.addEventListener('message', (e) => {
  console.log('收到广播消息:', e.data);
});

bc.postMessage('Hello, 全局广播!');
bc.postMessage({
  type: 'refresh',
  msg: '页面数据刷新',
  time: Date.now()
});

bc.close();

注意

  • 必须同名频道才能互通,不同频道完全隔离,互不干扰;
  • close() 仅关闭当前页面的实例连接,不会销毁全局频道,其他页面可正常通信。

浏览器兼容性:全局支持率 95.77%,全面兼容 Chrome、Edge、Firefox、新版移动端浏览器;不支持 IE 全系、Safari 15.3 及以下、iOS 15.3 及以下

优点:原生 API、使用极简、无中间层、支持多窗口、Tab 全局广播、数据格式无限制。

缺点:低版本 Safari 兼容差、仅支持同源通信。

Service Worker

核心原理:Service Worker 是独立于页面的后台代理进程,不受页面刷新、关闭影响。它可以获取当前作用域下所有打开的页面客户端,充当全局消息中转站,实现同源多页面统一广播。

// main.js
navigator.serviceWorker.register('/sw.js').then(() => {
    console.log('Service Worker 注册成功')
})

navigator.serviceWorker.addEventListener('message', (e) => {
    console.log('SW 全局广播消息:', e.data);
});

navigator.serviceWorker.controller?.postMessage('全局页面刷新通知');
// sw.js
self.addEventListener('message', (event) => {
    console.log(`[Client]接收页面消息:${event.data}`)
    event.waitUntil(
        self.clients.matchAll().then((clients) => {
            if (!clients || !clients.length) return
            clients.forEach((client) => {
                client.postMessage(event.data)
            })
        })
    )
})

浏览器兼容性:全局支持率 96.22%,仅 IE 全系不支持,兼容性优于 BroadcastChannel,是生产级同源广播优选方案。

优点:兼容性极佳、后台常驻不依赖页面、支持离线能力、全局广播稳定。

缺点:需要单独注册、配置文件、存在生命周期管理成本。

LocalStorage(推荐)

核心原理:所有同源页面共享同一套 LocalStorage 存储。当 LocalStorage 数据发生增删改时,会触发全局 storage 事件,除当前修改页面外,所有同源页面均可监听捕获,实现跨页面同步。

window.addEventListener('storage', (e) => {
  console.log(`[LocalStorage] 键名:${e.key},新值:${e.newValue},旧值:${e.oldValue}`)
})

window.localStorage.setItem('cross-msg', `页面同步消息-${Date.now()}`)

注意

  • 当前页面修改 LocalStorage,不会触发自身的 storage 事件;
  • 新旧数据完全一致时,浏览器不会触发事件,必须拼接时间戳保证更新;
  • LocalStorage 仅支持字符串存储,对象、数组需手动 JSON.stringify 序列化;
  • setItemremoveItemclear 均会触发全局变更事件。

优点:兼容性满分、零配置、开箱即用、无浏览器版本限制。

缺点:触发机制有局限、只能传字符串、高频同步性能较差。

SharedWorker(共享线程)

核心原理:SharedWorker 是浏览器多页面共享后台线程,区别于普通 Worker(单页面独占)。所有同源页面可共用同一个 SharedWorker,实现全局数据共享、消息互通,常驻后台不随页面刷新销毁。

// main.js
const sharedWorker = new SharedWorker('shared.worker.js', 'global-share')

sharedWorker.port.onmessage = (e) => {
    console.log('[SharedWorker] 接收共享数据:', e.data)
}

sharedWorker.port.postMessage({
    msg: '全局共享消息'
})

sharedWorker.port.postMessage({
    get: true
})
// shared.worker.js
var shareData = null
self.addEventListener('connect', (e) => {
    const port = e.ports[0]
    port.addEventListener('message', (event) => {
        if (event.data.get === true) {
            port.postMessage(shareData)
        } else {
            shareData = event.data
        }
    })
    port.start()
})

注意

  • 必须同一 worker 脚本文件才能实现共享,不同文件相互独立;
  • addEventListener 监听必须手动执行 port.start() 启动端口;
  • 可通过 chrome://inspect/#workers 调试共享线程代码。

浏览器兼容性:兼容性较差,IE、Safari、大部分移动端旧浏览器均不支持,业务场景极少使用。

优点:后台常驻、数据全局共享、刷新不丢失。

缺点:兼容性差、调试困难。

IndexedDB

原理与 LocalStorage 类似,属于浏览器端数据库级别的同源共享存储。

同源页面可读写同一 IndexedDB 数据库,通过页面可见事件、轮询、数据库更新事件实现跨页面数据同步。适合大容量、结构化、持久化数据共享,不适合轻量、高频的消息通信。

// 打开数据库
function openDB() {
  return new Promise((resolve) => {
    const req = indexedDB.open('CrossPageDB', 1);
    req.onupgradeneeded = e => {
      const db = e.target.result;
      if (!db.objectStoreNames.contains('msgStore')) {
        db.createObjectStore('msgStore', { keyPath: 'id' });
      }
    };
    req.onsuccess = e => resolve(e.target.result);
  })
}

// 写入消息
async function putMessage(msgObj) {
  const db = await openDB();
  const tx = db.transaction('msgStore', 'readwrite');
  tx.objectStore('msgStore').put({ id: Date.now(), ...msgObj });
  tx.commit();
  db.close();
}

// 读取全部消息
async function getMessages() {
  const db = await openDB();
  const tx = db.transaction('msgStore', 'readonly');
  const store = tx.objectStore('msgStore');
  const res = await store.getAll();
  db.close();
  return res;
}

// 使用:页面 A 写入
putMessage({ content: '跨页面消息', from: 'pageA' });

// 页面 B 在 visibilitychange 触发时拉取最新数据
document.addEventListener('visibilitychange', async () => {
  if (document.visibilityState === 'visible') {
    const list = await getMessages();
    console.log('IndexedDB 获取跨页面消息:', list);
  }
})

备注:IndexedDB 本身没有原生消息事件,一般配合 visibilitychange 页面显示事件或定时器轮询,完成跨页面数据同步。

非同源跨页面通信方案

以下为前端标准跨域页面通信方案,支持不同域名、不同端口、不同协议页面互通。

window.postMessage

核心原理:浏览器官方唯一允许跨域窗口通信的原生 API,只要页面存在关联(window.open 弹窗、iframe 内嵌),即可实现安全双向跨域通信。

targetWindow.postMessage(message, targetOrigin, [transfer]);
  • targetWindow:目标窗口引用(open 返回值、iframe.contentWindowwindow.opener)。
  • message:支持任意类型数据,浏览器自动结构化克隆。
  • targetOrigin:安全校验字段,精准限制目标域名,禁止随意使用 *

open

// parent.js
var targetWindow = window.open('http://localhost:5300/child.html?type=5')
window.addEventListener('message', (e) => {
    if (e.origin === 'http://localhost:5300') {
        console.log(`[postMessage]接收:${e.data}`)
    }
})
targetWindow.postMessage('Hello, 父页面消息!', 'http://localhost:5300')

// child.js
window.addEventListener('message', (e) => {
    console.log(`[子页面]接收:${e.data}`)
})
window.opener.postMessage('子页面回执', 'http://localhost:5200')

iframe

父页面域名:http://a.com:5200,iframe 子页面域名:http://b.com:5300

<!-- 父页面 a.html -->
<iframe id="crossIframe" src="http://b.com:5300/b.html"></iframe>
<script>
    const iframe = document.querySelector('#crossIframe');
    iframe.onload = function () {
        iframe.contentWindow.postMessage(
            { type: 'notify', data: '父页面发给 iframe 的跨域消息' },
            'http://b.com:5300'
        );
    };
    window.addEventListener('message', (e) => {
        if (e.origin === 'http://b.com:5300') {
            console.log('父页面收到 iframe 消息:', e.data);
        }
    })
</script>
<!-- iframe 子页面 b.html -->
<script>
    window.addEventListener('message', (e) => {
        if (e.origin !== 'http://a.com:5200') return;
        console.log('iframe 收到父页面消息:', e.data);

        window.parent.postMessage(
            { type: 'reply', data: 'iframe 回执消息' },
            'http://a.com:5200'
        );
    })
</script>

location.hash + iframe

核心原理:URL 中 hash(# 后面内容)的修改不会触发页面刷新,且支持跨域修改父/子页面 hash,配合 hashchange 事件实现跨域轻量通信。

限制:只能传递字符串,数据长度受 URL 长度限制;仅 hash 变化才触发事件。

父页面 http://a.com:5200/a.html,iframe 页面 http://b.com:5300/b.html

<!-- a.html 父页面 -->
<iframe id="hashIframe" src="http://b.com:5300/b.html"></iframe>
<script>
    const frame = document.querySelector('#hashIframe');

    function sendToIframe(msg) {
        frame.src = frame.src.split('#')[0] + `#${encodeURIComponent(msg)}`;
    }

    window.addEventListener('hashchange', () => {
        const raw = decodeURIComponent(window.location.hash.slice(1));
        console.log('父页面监听到 hash 变更,收到消息:', raw);
    })

    frame.onload = () => sendToIframe('HelloFromParent');
</script>
<!-- b.html iframe 子页面 -->
<script>
    window.addEventListener('hashchange', () => {
        const raw = decodeURIComponent(window.location.hash.slice(1));
        console.log('iframe 收到父页面 hash 消息:', raw);
    })

    function sendToParent(msg) {
        const base = 'http://a.com:5200/a.html';
        window.parent.location.href = `${base}#${encodeURIComponent(msg)}`;
    }

    setTimeout(() => {
        sendToParent('HelloFromIframe');
    }, 1000);
</script>

注意

  • 仅 hash 值发生变化才会触发事件,重复相同值不会触发;
  • window.parent.location.href 仅支持跨域赋值,不支持跨域取值
  • 传递中文、特殊字符务必使用 encodeURIComponentdecodeURIComponent

iframe + BroadcastChannel(终极方案)

实现原理:利用其中一个业务域名充当公共同源中转源,解决两个无关联跨域页面无法通信的问题。

  • 同源页面直接使用 BroadcastChannel 广播;
  • 跨域页面通过嵌入该域名下的隐藏中转 iframe,配合 postMessage 接入广播。

页面关系:

  • 页面 A(中转源域名):https://a.com/pageA.html
  • 页面 B(跨域页面):https://b.com/pageB.html
  • 中转页面(部署在 A 域名):https://a.com/a-transfer.html

业务页面 A:

<script>
    const bc = new BroadcastChannel('cross-transfer-channel');

    function sendMsg(data) {
        bc.postMessage(data);
    }

    bc.onmessage = function(e) {
        console.log('页面 A 接收跨域消息:', e.data);
    }

    sendMsg('Hello 我是页面 A');
</script>

跨域页面 B

<iframe src="https://a.com/a-transfer.html" style="display: none;"></iframe>
<script>
    window.addEventListener('message', (e) => {
        if (e.origin === 'https://a.com') {
            console.log('页面 B 接收广播消息:', e.data)
        }
    })

    function sendMsgToAll(data) {
        const iframe = document.querySelector('iframe')
        iframe.contentWindow.postMessage({
            type: 'broadcast',
            payload: data
        }, 'https://a.com')
    }

    sendMsgToAll('Hello 我是页面 B');
</script>

中转页面

<script>
    const bc = new BroadcastChannel('cross-transfer-channel');

    // 接收跨域页面 B 的消息,全局广播
    window.addEventListener('message', (e) => {
        if (e.origin !== 'https://b.com') {
            return
        }
        if (e.data.type === 'broadcast') {
            bc.postMessage(e.data.payload)
        }
    })

    // 接收全局广播,推送回当前跨域父页面
    bc.onmessage = (e) => {
        window.parent.postMessage(e.data, '*')
    }
</script>

核心特点

  • 不需要独立中转域名,复用现有业务域名部署中转静态页面,减少运维成本。
  • 实现无引用关系的跨域顶层页面广播通信,页面之间没有 window 引用也可以互通。
  • 同源页面直接使用 BroadcastChannel,跨域页面仅嵌入隐藏 iframe 即可接入,新增跨域页面接入成本低。
  • 纯前端实现,不依赖后端服务。

辅助通信方案

URL 参数传参

页面跳转、新开页面时通过 ?key=value 拼接参数传值。

特点单向一次性通信,只能前页传后页,无法反向、无法实时同步。

WebSocket

依托服务端长连接作为消息中转中心,所有页面连接同一 WS 服务,由服务端统一广播消息。

特点:支持跨页面、跨域名、跨设备实时双向通信,适用于聊天、实时协作、大屏同步等场景。

通信方案整体分析

各方案核心特点

  • BroadcastChannel:同源多窗口广播模式,代码简洁,兼容性中等,低版本 Safari 不支持;
  • Service Worker:同源全局广播,兼容性最好,稳定可靠;
  • LocalStorage:同源广播,兼容性满分,有触发限制;
  • Shared Worker:同源数据共享模式,需主动取值,兼容性差;
  • IndexedDB:同源大容量数据共享,适合持久化存储,无原生消息事件;
  • postMessage:通用跨域通信,支持关联窗口、iframe,兼容性极佳;
  • location.hash + iframe:轻量跨域通信,适合简单字符串状态同步,受 URL 长度限制;
  • 跨域 iframe + BroadcastChannel 中转:解决无关联顶层页面跨域广播,需在同源域名部署中转静态页;
  • URL 参数、WebSocket:特殊场景补充方案。

数据同步触发方式

  • 事件触发:BroadcastChannel、storage、message、hashchange;
  • 主动轮询:定时器轮询存储、数据库;
  • 页面生命周期触发:visibilitychange、pageshow 页面显示刷新数据。

总结

  • 同一窗口同源页面通信:优先 LocalStorage;
  • 多 Tab、多窗口同源全局同步:优先 BroadcastChannel、Service Worker;
  • 弹窗登录、跨窗口授权回传:postMessage + window.open;
  • iframe 父子跨域通信:postMessage、location.hash
  • 两个无关联顶层页面跨域广播:iframe 中转 + BroadcastChannel。

参考资料

MDN BroadcastChannel

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-08-23 13:24:36

results matching ""

    No results matching ""