1. 首页
  2. IT资讯

postMessage应用一下

摘要: 了解过postMessage, 但一直没发现哪些场景需要使用它,

最近一个小项目, 需要通过iframe, 嵌入到一个已经存在的Vue项目的系统中,

涉及iframe的参数传递, 这时发现postMessage的威力.

  • 需求

传统的后台管理系统布局, 我的小项目需要嵌入到白色区域,
外层的系统会通过路由跳转到这个界面.

postMessage应用一下
  • 问题1 路由参数的传递

父级系统通过路由跳转过来, 并携带参数, iframe引入的小项目需要获得父级路由的参数.

跳转时携带参数通过query的方式, 防止跳转后刷新获取不到参数问题.

methods:{     setting (ele) {         this.$router.push({             path: 'iframes',             query: {                 deviceId: ele.deviceId             }         })     } } 

展示iframe的路由界面. iframe标签引入项目.

<div class="bot">     <div class="bot-left">         <left-nav></left-nav>     </div>     <div class="bot-right">        <div class="iframeContent">            <iframe src="http://10.1.54.36:8080/" ref='xmIframe' frameborder="0"></iframe>        </div>     </div> </div>

然后就是iframe内部的项目如何获得父级项目的路由参数, 敲黑板…

iframe加载完成后, 也就是load事件触发.

获取iframe的contentWindow, 调用postMessage发送路由参数.

mounted(){     let xmIframe = this.$refs['xmIframe'];     xmIframe.addEventListener('load', () => {         // iframe加载后, 向iframe发送参数         let iframeWin = xmIframe.contentWindow;         iframeWin.postMessage({             method: 'xmParams',             data: {                 deviceId: this.$route.query.deviceId             }         }, '*');     }); } // postMessage的第一个参数为发送的数据, 可以为Number, String , Object等,  // 第二个参数与为发送到的window的地址, 类似同源策略, 需协议, ip, 端口一致, 才能接收到, // 第二个参数设置为*代表不限制网站地址 

在被iframe引入的小项目中, 监听window的message事件, 并判断method, 获取参数.

mounted () {   window.addEventListener('message', (e) => {     if (e.data.method === 'xmParams') {       this.deviceId = e.data.data.deviceId; // 本地保存设备id       this.getOldCfg(this.deviceId); // 获取设备当前的配置, 进行数据展示     }   }); } 

这样, 在iframe加载完成后, iframe内部的网站在message事件中,

获得设备deviceId, 进而做后续相应处理, 请求当前配置, 信息展示等.

  • 问题2 居中弹框和背景层的显示

小项目未被引入时, 点击保存弹出全屏背景层, 弹出框水平垂直居中, 居中css代码如下:

.confirm{   position: fixed;   width: 400px;   height: 200px;   left: 50%;   top: 50%;   padding: 20px;   z-index: 2;   transform: translate(-50%, -50%);   text-align: center;   background-color: #fff; }

未被引入时效果:

postMessage应用一下

引入后的效果:

postMessage应用一下

问题来了, iframe引入的页面和父级的页面, 是相互独立的, 各自有各自的window, 路由等.

两个地方需要修复, 1 弹框未全屏居中, 2 背景层未覆盖全屏.

1 针对弹框未全屏居中, 我的处理方式是: 在向iframe传递参数时, 父级左侧的宽度和顶部的高度也传递给iframe, iframe内部再根据传入的尺寸调整居中框的位置.

具体实现-发送代码:

mounted(){     let xmIframe = this.$refs['xmIframe'];     xmIframe.addEventListener('load', () => {         // iframe加载后, 向iframe发送请求参数         let iframeWin = xmIframe.contentWindow;         iframeWin.postMessage({             method: 'xmParams',             data: {                 deviceId: this.$route.query.deviceId             }         }, '*');         iframeWin.postMessage({             method: 'navSize',             data: {                 width: 180,                 height: 70             }         }, '*');     }); } 

就收并处理代码:

mounted () {   window.addEventListener('message', (e) => {     if (e.data.method === 'xmParams') {       this.deviceId = e.data.data.deviceId;// 本地保存设备id       this.getOldCfg(this.deviceId);// 获取设备当前的配置, 进行展示     } else if (e.data.method === 'navSize') {       this.offset = e.data.data; // 本地存储     }   }); } 

点击确认时, 根据offset调整位置

<div class='form-item'>   <button type='button' @click='save'>保存</button> </div>

———————————————————————————————–

save () {   this.model = true;   let dialog = document.getElementsByClassName('confirm')[0];   dialog.style.left = 'calc(50% - ' + this.offset.width / 2 + 'px)';   dialog.style.top = 'calc(50% - ' + this.offset.height / 2 + 'px)'; } 

便可实现弹框的距中:

postMessage应用一下

2 针对背景层问题, 我的解决方式是: 既然iframe的背景层不能覆盖父级的dom, 那就让父级的背景层自己去覆盖, iframe要做的就是通知父级, 何时弹出背景层, 何时隐藏背景层.

先在父级加一个全屏背景层, 通过变量控制显示隐藏.

<div class="bot">     <div class="bot-left">         <left-nav></left-nav>     </div>     <div class="bot-right">         <iframe src="http://10.1.54.211:8082/" ref='xmIframe' frameborder="0"></iframe>     </div>     <div class="bg" v-show='bgFlag'></div> </div>

=======================================================

data () {     return {      	bgFlag: false     } } 

然后, 在父级页面监听message事件的触发, 内部判断消息类型, 改变bgFlag的状态.

window.addEventListener('message', (e) => {     if (e.data.method === 'showBg') {         this.bgFlag = true;     } else if (e.data.method === 'hideBg') {         this.bgFlag = false;     } }); 

最后, 就是在被引入的页面内, 当弹出框出现时, 通知父级页面, 显示背景层. 当弹出框消失时, 通知父级隐藏背景层.

点击保存, 发送showBg消息.

save () {   this.model = true;   // 调整弹出框的位置   let dialog = document.getElementsByClassName('confirm')[0];   dialog.style.left = 'calc(50% - ' + this.offset.width / 2 + 'px)';   dialog.style.top = 'calc(50% - ' + this.offset.height / 2 + 'px)';   // 通知父级显示背景层   window.parent.postMessage({     method: 'showBg',   }, '*'); } 

点击取消或确认保存, 发送hideBg消息.

cancel () {   this.model = false;   // 通知父级, 隐藏背景层   window.parent.postMessage({     method: 'hideBg',   }, '*'); }, confirmSave () {   this.model = false;   console.log('发送数据');   // 通知父级, 隐藏背景层   window.parent.postMessage({     method: 'hideBg',   }, '*');   return false; } 

这样就能保证背景层的全屏覆盖效果.

postMessage应用一下

目前遇到的两个问题, 通过上述方式解决, 考虑到安全性问题, postMessag的第二个参数尽量指定明确的地址.

对于iframe页面内使用 window.parent发送postMessage消息.

以及嵌入iframe的页面使用xmIframe.contentWindow发送postMessage消息,

两者不是使用本页面的window发送, 在MDN上, 找到这样的说明:

从广义上讲,一个窗口可以获得对另一个窗口的引用(比如targetWindow = window.opener),然后在窗口上调用targetWindow.postMessage() 方法分发一个 MessageEvent消息。接收消息的窗口可以根据需要自由处理此事件。

附上MDN的postMessage地址: postMessage

测试使用的两个Vue项目地址: github测试代码下载

原文始发于:postMessage应用一下

主题测试文章,只做测试使用。发布者:酒颂,转转请注明出处:http://www.cxybcw.com/24898.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code