1.0在使用过程中存在很多问题
1.同时发送多个postMessage请求的时候,回调属于异步执行,会不知道谁返回的
2.子页面同名订阅时,后面的会覆盖前面队列中的方法
下面是2.0的封装及示例,请查收
这次是在vue环境中调试的
postmessage.js
/**
* @author Saryz
* iframe solution
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.postmessage = factory())
}(this, function () {
const commonMethod = 'haha'
// 管道集合
const queueMap = new Map()
// 全局监听
console.log('【siframe】【addEventListener】当前页面:', location.href)
let postMessageListenerFlag = false
if (!postMessageListenerFlag) {
window.addEventListener('message', function (event) {
postMessageListenerFlag = true
// 事件过滤
if (event.data.type !== 'S-IFRAME') return
// 来源页面地址
const sourceUrl = event.data.sourceUrl
console.log('【siframe】【addEventListenerCallBack】', event)
// 执行集合中方法
queueMap.get(event.data.method + sourceUrl).fn(event.data.data)
})
}
/**
* 给子页面传值
* @param {*} iframe
* @param {*} methodName
* @param {*} data
*/
function postToIframe (iframe, methodName, data, fn) {
// 目标iframe地址 通常指子页面地址
const iframeUrl = iframe.getAttribute('src') || iframe
console.log('【siframe】【postToIframe】from', location.href, 'to', iframeUrl)
iframe.contentWindow.postMessage({
method: methodName || commonMethod,
data: data,
type: 'S-IFRAME',
sourceUrl: iframe.src
}, '*')
// 注册回调方法
fn && listen(methodName, fn, iframe)
}
/**
* 给父级页面传值
* @param {*} methodName
* @param {*} data
*/
function postToParent (methodName, data, fn) {
console.log('【siframe】【postToParent】from', location.href, 'to parent')
window.parent.postMessage({
method: methodName || commonMethod,
data: data,
type: 'S-IFRAME',
sourceUrl: window.location.href
}, '*')
// 注册回调方法
fn && listen(methodName, fn)
}
/**
* 注册监听事件
* @param methodName
* @param fn
* @param iframe
*/
function listen (methodName, fn, iframe) {
const hostUrl = iframe ? iframe.src : location.href
queueMap.set(methodName + hostUrl, { fn })
console.log('【siframe】【listen】【hostUrl】', hostUrl, '【queueMap】', queueMap)
}
/**
* 发送消息
* @param iframe
* @param methodName
* @param data
* @param fn
*/
function trigger (iframe, methodName, data, fn) {
if (iframe) {
postToIframe(iframe, methodName, data, fn)
} else {
postToParent(methodName, data, fn)
}
}
return {
listen,
trigger
}
}))
parent.vue
<template>
<div class="page">
<p>Parent
<button @click="checkChildForm">checkChildForm</button>
</p>
<div class="iframe_box" v-for="(item,index) in iframesList" :key="item.id">
<iframe :ref="'iframe'+index" :src="item.path" frameborder="0" :name="'name'+item.id"></iframe>
</div>
</div>
</template>
<script>
export default {
name: 'parent',
data () {
return {
iframesList: [
{
id: 1,
path: 'http://192.168.43.181:8081/#/child1'
},
{
id: 2,
path: 'http://192.168.43.181:8081/#/child2'
}
],
form: {
name: 'parent',
sex: '1',
brithday: '20200202'
}
}
},
created () {
},
mounted () {
const iframeDom = this.$refs
const that = this
Object.keys(iframeDom).forEach(key => {
postmessage.listen('getPersonInfo', function (data) {
postmessage.trigger(iframeDom[key][0], 'getPersonInfo', that.form)
}, iframeDom[key][0])
})
},
methods: {
checkChildForm () {
console.log('parent发消息')
Object.keys(this.$refs).forEach(key => {
console.log('postmessage', key)
postmessage.trigger(this.$refs[key][0], 'checkChildForm', { p: 'parent checkForm' }, (data) => {
console.log(key + 'parent postmessage trigger checkChildForm callback', data)
})
})
}
}
}
</script>
<style lang="scss" type="text/scss" scoped>
.page {
padding: 20px;
width: 80vw;
height: 80vh;
background: #2c3e50;
position: fixed;
left: 50%;
top: 50%;
margin-left: -40vw;
margin-top: -40vh;
color: #fff;
}
iframe {
width: 200px;
height: 200px;
background: #fff;
}
.iframe_box {
margin-bottom: 10px;
}
</style>
child1.vue
<template>
<div>
<p>child1</p>
<button @click="getPersonInfo">getPersonInfo</button>
</div>
</template>
<script>
export default {
name: 'child1',
data () {
return {}
},
created () {
const form = { name: 'child1' }
const getFormKey = 'checkChildForm'
postmessage.listen(getFormKey, function (data) {
console.log('child1 checkChildForm方法', '当前收件人' + location.href, '收到了消息', data)
postmessage.trigger(null, getFormKey, form)
})
},
methods: {
getPersonInfo () {
console.log('child1 getPersonInfo========>')
postmessage.trigger(null, 'getPersonInfo', { name: 'child1' }, result => {
console.log('我是' + location.href, '我拿到了从父级得到的数据Person', result)
})
}
}
}
</script>
<style lang="scss" type="text/scss" scoped>
</style>
child2.vue
<template>
<div>
<p>child2</p>
<button @click="getPersonInfo">getPersonInfo</button>
</div>
</template>
<script>
export default {
name: 'child2',
data () {
return {}
},
created () {
const form = { name: 'child2' }
const getFormKey = 'checkChildForm'
postmessage.listen(getFormKey, function (data) {
console.log('child2 checkChildForm方法', '当前收件人' + location.href, '收到了消息', data)
postmessage.trigger(null, getFormKey, form)
})
},
methods: {
getPersonInfo () {
console.log('child2 getPersonInfo========>')
postmessage.trigger(null, 'getPersonInfo', { name: 'child2' }, result => {
console.log('我是' + location.href, '我拿到了从父级得到的数据Person', result)
})
}
}
}
</script>
<style lang="scss" type="text/scss" scoped>
</style>