一、前言

最近需求有跨标签页操作,借此总结跨窗口(标签页)通信的常用方法,包括同源和跨域两种情况,给出的示例代码能让你快速上手。

二、同源

localStorage 配合 storage 事件:简单、兼容性好

 1window.addEventListener('storage', (e) => {
 2    
 3    if (e.key != 'wc') return;
 4    const data = JSON.parse(e.newValue);
 5    console.log(data);
 6});
 7
 8const data = {
 9    a: 111,
10    now: Date.now(), 
11};
12localStorage.setItem('wc', JSON.stringify(data));

Broadcast Channel API:功能全

 1
 2const channel = new BroadcastChannel('test_channel');
 3
 4channel.addEventListener('message', (e) => {
 5    console.log(e.data);
 6});
 7
 8channel.addEventListener('messageerror', (e) => {
 9    console.error(e);
10});
11
12channel.postMessage({
13    url: location.href,
14    data: '123',
15});
16
17

三、跨域

利用 iframe 的 postmessage 接口

parent.html(注意修改子页面的 iframe 地址)

 1<!DOCTYPE html>
 2<html>
 3<head>
 4  <meta charset='UTF-8'>
 5  <meta name="viewport" content="width=device-width,initial-scale=1" />
 6  <title>Document</title>
 7  <style>
 8    #theIframe {
 9      width: 450px;
10      height: 200px;
11    }
12  </style>
13</head>
14<body>
15  <h1>Parent</h1>
16  <button id="sendBtn">发送消息给子页面</button>
17  <p>收到消息:<span id="msg"></span></p>
18  
19  <iframe src="http://localhost:7002/iframe/child.html" id="theIframe"></iframe>
20
21  <script>
22    
23    const IFRAME_SOURCE = 'http://localhost:7002';
24
25    theIframe.addEventListener('load', () => {
26      try {
27        
28        theIframe.contentDocument.body.prepend("Hello, world!");
29      } catch (err) {
30        console.log('iframe 跨域');
31      }
32
33      sendBtn.addEventListener('click', () => {
34        
35        theIframe.contentWindow.postMessage({ command: 'show-text', text: '1' }, IFRAME_SOURCE);
36      });
37    });
38
39    
40    window.addEventListener('message', (e) => {
41      
42      if (e.origin !== IFRAME_SOURCE) return;
43
44      
45      const { command, text } = e.data;
46      switch (command) {
47        case 'show-text':
48          msg.textContent = text;
49          break;
50      }
51    });
52  </script>
53</body>
54</html>
55

child.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4  <meta charset='UTF-8'>
 5  <meta name="viewport" content="width=device-width,initial-scale=1" />
 6  <title>Document</title>
 7</head>
 8<body>
 9  <h1>Child</h1>
10  <button id="sendBtn">发送消息给父页面</button>
11  <p>收到消息:<span id="msg"></span></p>
12
13  <script>
14    
15    const PARENT_SOURCE = 'http://localhost:7001';
16
17    sendBtn.addEventListener('click', () => {
18      
19      window.parent.postMessage({ command: 'show-text', text: '3' }, PARENT_SOURCE);
20    });
21
22    
23    window.addEventListener('message', (e) => {
24      if (e.origin !== PARENT_SOURCE) return;
25      const { command, text } = e.data;
26      switch (command) {
27        case 'show-text':
28          msg.textContent = text;
29          break;
30      }
31
32      
33      setTimeout(() => {
34        e.source.postMessage({ command: 'show-text', text: '2' }, e.origin);
35      }, 1000);
36    });
37  </script>
38</body>
39</html>
40

启动示例:

 1启动子页面服务npx serve -l 7002
 2启动父页面服务npx serve -l 7001
 3最后访问父页面即可

如果帮到你了,可以点个赞,欢迎交流沟通。

个人笔记记录 2021 ~ 2025