message 是浏览器跨文档/跨窗口消息通信的原生事件。
基本概念
// 发送消息
targetWindow.postMessage(data, targetOrigin)
// 接收消息
window.addEventListener('message', (event) => {
// event 包含三个重要属性
})
event 对象的三个核心属性
| 属性 | 说明 | 示例 |
|---|---|---|
event.data |
传递的数据 | { name: 'spin' } |
event.origin |
发送方的源(协议+域名+端口) | 'https://softool.cn' |
event.source |
发送方的窗口引用 | window, iframe.contentWindow |
在 SW 中的应用
// 发送方(可以是任何窗口)
window.opener.postMessage({ name: 'spin' }, '*')
// 接收方(SW.vue)
window.addEventListener('message', (event) => {
if (event.data?.name === 'spin') {
triggerSpin()
}
})
常见使用场景
1. 父子 窗口通信
// 父窗口 → iframe
document.getElementById('myIframe').contentWindow
.postMessage({ action: 'spin' }, 'https://child.com')
// iframe → 父窗口
window.parent.postMessage({ action: 'done' }, 'https://parent.com')
2. 弹出 窗口通信
// 主窗口 → 弹出窗口
const popup = window.open('https://example.com')
popup.postMessage({ name: 'spin' }, 'https://example.com')
// 弹出窗口 → 主窗口
window.opener.postMessage({ result: 'winner' }, 'https://main.com')
3. 浏览器扩展通信
// 内容脚本 → 后台脚本
chrome.runtime.sendMessage({ action: 'spinWheel' })
安全注意事项
// ❌ 不安全:接受所有来源的消息
window.addEventListener('message', (event) => {
triggerSpin() // 任何人都能触发
})
// ✅ 安全:验证消息来源
const ALLOWED_ORIGINS = ['https://softool.cn', 'https://localhost:5173']
window.addEventListener('message', (event) => {
if (!ALLOWED_ORIGINS.includes(event.origin)) return
if (event.data?.name === 'spin') triggerSpin()
})
与 SW 的其他触发方式对比
| 触发方式 | 使用场景 | 安全性 |
|---|---|---|
| 点击 Canvas | 用户手动操作 | ✅ 安全 |
| Ctrl+Enter | 键盘快捷键 | ✅ 安全 |
| postMessage | 跨窗口通信 | ⚠️ 需验证 origin |
| ref.spin() | 父组件调用 | ✅ 安全 |
总结: message 事件是浏览器原生的跨窗口通信机制,postMessage 发送,addEventListener('message') 接收。在 SW 中主要用于支持从其他窗口远程触发旋转,使用时务必验证 event.origin 确保安全。
