Skip to content

跨页面通信

跨域页面分为两种:

  • 不同标签页间通信
  • iframe 的页面通信

1. localStorage + storage 事件实现

因为 storage 事件是可以跨标签页的,所以我们可以通过在页面中监听 storage 事件进行数据传递。

假设我们需要从 A 页面发送数据给 B 页面

页面 A:

JS
// A 页面有个 btn 按钮,我们写入数据到存储中
btn.addEventListener("click", () => {
  localStorage.setItem("message", "hello world")
})
// A 页面有个 btn 按钮,我们写入数据到存储中
btn.addEventListener("click", () => {
  localStorage.setItem("message", "hello world")
})

页面 B:

JS
// B 页面监听存储的变化,获取到对应的值
window.addEventListener("storage", (e) => {
  // e 是一个 StorageEvent 事件对象,内部有多种属性,主要用到的属性如下
  // newValue 改变后的值
  // oldValue 原有的值
  // key 存储字段的属性 key,这里是对应上面的 message
  const { newValue, oldValue, key } = e
})
// B 页面监听存储的变化,获取到对应的值
window.addEventListener("storage", (e) => {
  // e 是一个 StorageEvent 事件对象,内部有多种属性,主要用到的属性如下
  // newValue 改变后的值
  // oldValue 原有的值
  // key 存储字段的属性 key,这里是对应上面的 message
  const { newValue, oldValue, key } = e
})

注意:

  • 页面需要同源,sessionStorage 在不同标签页中是无法触发 storage 事件的,因为他们不共享,只有在 iframe 页面中才行。
  • 如果只有一个页面,也无法触发 storage 事件,必须是1个以上标签页中才能进行监听(虽然一个页面时直接修改浏览器的 storage 值会触发,但是使用代码是无法触发的)

2. 使用 websocket

websocket 协议是一个全双工通信的协议,客户端和服务端可以互相通信。

页面 A:

JS
// 创建 websocket 连接  
var ws = new WebSocket('ws://localhost:3000/');

// A 页面有个 btn 按钮,向服务端发送消息
btn.addEventListener("click", () => {
  ws.send('hello world')
})
// 创建 websocket 连接  
var ws = new WebSocket('ws://localhost:3000/');

// A 页面有个 btn 按钮,向服务端发送消息
btn.addEventListener("click", () => {
  ws.send('hello world')
})

页面 B:

JS
var ws = new WebSocket('ws://localhost:3000/');

// 接受服务器端转发过来的消息
ws.onmessage = function (e) {
  console.log(e.data) // hello world
}
var ws = new WebSocket('ws://localhost:3000/');

// 接受服务器端转发过来的消息
ws.onmessage = function (e) {
  console.log(e.data) // hello world
}

没有同源共享策略限制,可跨域共享

3. sharedWorker

sharedWorkerwebWorker 的一种,其可在同源页面中共享;如果多个页面的 url 一致,则只会创建一个sharedWorker,多个页面共享这个 sharedWorker

worker.js

JS
const set = new Set() // 创建一个不重复的变量

onconnect = event => {
  const port = event.ports[0]
  set.add(port)

  // 接收信息
  port.onmessage = e => {
    // 广播信息
    set.forEach(p => {
      p.postMessage(e.data)
    })
  }

  // 发送信息
  port.postMessage("worker 广播信息")
}
const set = new Set() // 创建一个不重复的变量

onconnect = event => {
  const port = event.ports[0]
  set.add(port)

  // 接收信息
  port.onmessage = e => {
    // 广播信息
    set.forEach(p => {
      p.postMessage(e.data)
    })
  }

  // 发送信息
  port.postMessage("worker 广播信息")
}

页面 A:

JS
const worker = new SharedWorker('./worker.js')

btn.addEventListener("click", () => {
  // 发送消息
  worker.port.postMessage('hello world')
})
const worker = new SharedWorker('./worker.js')

btn.addEventListener("click", () => {
  // 发送消息
  worker.port.postMessage('hello world')
})

页面 B:

js
const worker = new SharedWorker('./worker.js')
// 接收消息
worker.port.onmessage = e => {
  console.info(e.data) // hello world
}
const worker = new SharedWorker('./worker.js')
// 接收消息
worker.port.onmessage = e => {
  console.info(e.data) // hello world
}

利用 cookie 的同源共享特点,使用定时器轮询查看内容是否变更。

页面 A:

JS
// 使用定时器每秒获取一次 cookie 信息,根据业务需求对比内容是否变更
setInterval(() => {
  console.log("cookie", document.cookie)
}, 1000);
// 使用定时器每秒获取一次 cookie 信息,根据业务需求对比内容是否变更
setInterval(() => {
  console.log("cookie", document.cookie)
}, 1000);

页面 B:

JS
btn.addEventListener("click", () => {
  document.cookie = 'hello world'
})
btn.addEventListener("click", () => {
  document.cookie = 'hello world'
})

总结

实现优点缺点
localStorage简单且易于理解不能跨域
websocket可跨域,内容无限制需要服务端配合
sharedWorker性能好,原生支持不能跨域,兼容性一般
cookie + setInterval-存储大小限制,且会随请求携带

iframe 间通信