Vue进阶(九十二):应用 postMessage 实现窗口通信

本文深入讲解了前端开发中跨窗口通信的重要技术postMessage。详细解释了其语法与参数,包括如何在不同域名间安全地传递消息,以及如何利用window对象进行有效调用。并通过实例演示了如何在父窗口与子窗口间进行双向通信。
该文章已生成可运行项目,


一、拓展阅读

在前端应用中,窗口间通信应用场景很多,比如弹出qq登录认证窗。在这里插入图片描述

二、postMessage 语法

window.postMessage(msg,targetOrigin)

注意⚠️postMessage要通过window对象调用!因为这里的window不只是当前window!大部分使用postMessage的时候,都不是本页面的window,而是其他网页的window!如:

  1. iframecontentWindow
  2. 通过window.open方法打开新窗口的window
  3. window.opener

如果你使用postMessage时没有带window,就是用的本页面的window来调用它。

2.1 参数说明

msg

这是要传递的消息。它可以是一切javascript参数,如字符串,数字,对象,数组,而不是和json一样只局限于字符串。

targetOrigin

这个参数称作“目标域”,注意⚠️,是目标域不是本域!比如,你想在2.com的网页上往1.com网页上传消息,那么这个参数就是“http://1.com/”,而不是2.com.

另外,一个完整的域包括:协议,主机名,端口号。如:http://g.cn:80/

window.open方法会返回一个窗口对象,使用这个对象可以向子窗口发送消息,而子窗口可以通过window.opener向父窗口发送消息,示例如下:

// index.html
<body>
    <button onclick="opwin()">打开</button>
    <script type="text/javascript">
	    function opwin() {
	        //保留窗口对象
	        var popup = window.open("test.html", "_blank");
	    }
	    function receiveMessage(event) {
	        //event.origin是指发送的消息源,一定要进行验证!!!
	        if (event.origin !== "http://localhost")return;
	        //event.data是发送过来的消息。
	        console.log(event.data);
	        //event.source是指子窗口,主动向子窗口发送消息可以用popup
	        //postMessage有两个参数,消息和自己的源(例如http://www.baidu.com),自己的源应该和目标源相同。否则发送会失败。
	        event.source.postMessage("我是主窗口,我接收到消息了",window.location);
	    }
	    //添加消息接收函数
	    window.addEventListener("message", receiveMessage, false);
    </script>
</body>
// test.html
<body>
    <button onclick="send()">发送</button>
    <script type="text/javascript">
	    function send() {
	        //window.opener指的就是父窗口(打开本窗口的窗口)
	        window.opener.postMessage("我是子窗口,向主窗口发送消息", window.location);
	    }
	    function receiveMessage(event) {
	        if (event.origin !== "http://localhost")return;
	        console.log(event.data);
	    }
	    window.addEventListener("message", receiveMessage, false);
    </script>
</body>

由于postMessage是通过网络协议,所以不能以直接在浏览器以打开html的方式进行调试。而是应该放在服务器上,走网络协议。

三、拓展阅读

本文章已经生成可运行项目
<think>好的,我现在需要解决用户的问题:如何在Vue3中使用postMessage给iframe传递参数。用户之前已经询问过外层向iframe传递参数的一般方法,现在具体到Vue3框架,可能需要更具体的实现步骤。 首先,我得回顾一下之前回答的内容。之前的回答涵盖了通用的JavaScript方法,包括postMessage、URL参数和直接变量访问,还提到了安全性、性能优化和现代框架集成的示例,比如React。现在用户需要的是Vue3的示例,所以应该调整示例代码,使用Vue3的语法,比如Composition API,使用ref和onMounted等钩子函数。 接下来,我需要考虑用户可能的实际场景。用户可能在开发一个包含iframe的Vue3应用,需要动态地向子iframe发送数据,比如表单输入、用户操作触发的参数变化。因此,示例需要展示如何监听数据变化并实时发送到iframe。 还要注意Vue3的特性,比如响应式系统。用户可能希望当父组件中的数据变化时,自动触发postMessage。这时候应该使用watch或watchEffect来监听数据变化,并在变化时发送消息。 另外,安全性方面需要再次强调验证event.origin,防止恶意iframe窃取数据。同时,在Vue3中,组件卸载时应该移除事件监听器,避免内存泄漏。因此,在子iframe的onUnmounted钩子中移除message事件监听是必要的。 用户可能还关心如何接收参数后的处理,比如在子组件中如何更新状态。示例中应该展示如何在子iframe中使用Vue3的响应式变量(如ref)来保存接收到的数据,并更新UI。 还要考虑跨域的情况,虽然用户可能知道同源策略,但需要明确postMessage的目标origin参数,可以是具体的域名或通配符'*',但出于安全考虑,建议指定确切域名。 可能还需要提到TypeScript的支持,因为Vue3项目可能使用TypeScript,所以在示例中添加类型声明会更好,比如使用CustomEvent和消息数据结构。 最后,确保代码示例正确,比如在父组件中获取iframe元素的方式,可能需要使用模板引用(ref),并且在onMounted之后确保iframe已经加载完成,避免获取不到contentWindow的问题。 总结一下,回答需要包括以下几个部分: 1. Vue3父组件发送消息的步骤,使用Composition API,ref引用iframe,watch监听数据变化。 2. 子iframe接收消息的处理,验证origin,更新响应式数据。 3. 生命周期管理,卸载时移除监听。 4. 安全性和最佳实践。 5. 可能的扩展,比如使用TypeScript,处理加载完成事件等。</think>以下是Vue3中使用postMessage与iframe通信的详细实现方法,采用Composition API语法: --- ### 一、父组件发送参数 ```vue <!-- Parent.vue --> <template> <div> <input v-model="message" @input="sendToIframe" /> <iframe ref="iframeRef" src="./child.html" @load="onIframeLoad" /> </div> </template> <script setup> import { ref, watch } from 'vue' const iframeRef = ref(null) const message = ref('初始值') // 自动监听变化发送 watch(message, (newVal) => { sendToIframe(newVal) }) // 手动触发发送 const sendToIframe = (data) => { if (!iframeRef.value) return iframeRef.value.contentWindow?.postMessage( { type: 'PARENT_MSG', payload: data }, 'https://your-iframe-domain.com' // 替换为实际域名 ) } // 确保iframe加载完成 const onIframeLoad = () => { sendToIframe(message.value) } </script> ``` --- ### 二、子iframe接收参数 ```vue <!-- Child.vue (iframe内部) --> <template> <div>接收到的参数:{{ receivedData }}</div> </template> <script setup> import { ref, onMounted, onUnmounted } from 'vue' const receivedData = ref('') const handleMessage = (event) => { // 安全验证 if (event.origin !== 'https://parent-domain.com') return // 验证消息结构 if (event.data?.type === 'PARENT_MSG') { receivedData.value = event.data.payload } } onMounted(() => { window.addEventListener('message', handleMessage) }) onUnmounted(() => { window.removeEventListener('message', handleMessage) }) </script> ``` --- ### 三、进阶优化方案 1. **TypeScript支持**: ```typescript interface MessageEvent<T = any> extends Event { data: T origin: string // ...其他标准属性 } interface CustomMessage { type: string payload: string } ``` 2. **防抖处理高频更新**: ```javascript import { watch, debounce } from 'lodash-es' watch( message, debounce((newVal) => { sendToIframe(newVal) }, 300) ) ``` 3. **双向通信扩展**: ```javascript // 子iframe发送消息 const sendToParent = () => { window.parent.postMessage( { type: 'CHILD_MSG', payload: '来自子窗口' }, 'https://parent-domain.com' ) } // 父组件接收 window.addEventListener('message', (event) => { if (event.origin !== 'https://child-domain.com') return console.log('来自子窗口:', event.data) }) ``` --- ### 四、关键注意事项 1. **安全规范**: - 始终验证`event.origin` - 敏感数据需加密处理 - 使用特定消息类型标识(如`PARENT_MSG`) 2. **生命周期管理**: ```javascript // 父组件卸载时清除 onUnmounted(() => { window.removeEventListener('message', handleChildMessage) }) ``` 3. **错误处理**: ```javascript try { iframeRef.value.contentWindow.postMessage(...) } catch (error) { console.error('通信失败:', error) } ``` --- ### 五、完整工作流程 1. 父组件通过`ref`获取iframe DOM引用 2. 使用`watch`监听响应式数据变化 3. 通过`contentWindow.postMessage`发送结构化数据 4. 子iframe通过`message`事件监听 5. 双方进行来源验证和数据格式校验 6. 更新对应组件的响应式状态 --- 通过这种实现方式,可以实现: ✅ 安全可控的跨窗口通信 ✅ 响应式数据自动同步 ✅ 完善的错误处理机制 ✅ 符合Vue3的最佳实践
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

No Silver Bullet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值