index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- <script src="../build/postMessage.js"></script> -->
<style>
html, body{
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: tan;
}
.wrapper{
width: 100%;
height: 100%;
padding-top: 50px;
box-sizing: border-box;
position: relative;
}
.header{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 50px;
background: tomato;
box-sizing: border-box;
padding: 0 10px;
}
.header > button{
margin-top: 10px;
}
.content{
width: 100%;
height: 100%;
}
.content iframe{
width: 100%;
height: 100%;
overflow: auto;
margin: -2px 0;
background: white;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="header">
<button onclick="handleSendMessage()">向下发起通知[emit]</button>
接收的数据[on]: <span id="msg"></span>
</div>
<div class="content">
<iframe src="./iframe.html" frameborder="0" id="iframe"></iframe>
</div>
</div>
<script>
if (!Array.prototype.findIndex) {
Object.defineProperty(Array.prototype, 'findIndex', {
value: function (predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return k.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return k;
}
// e. Increase k by 1.
k++;
}
// 7. Return -1.
return -1;
}
});
}
const uuid = () => Math.random().toString(36).substr(2) + Date.now().toString(36)
const handleEmit = function ({ $request, params }) {
debugger
const eventPool = this.eventPool[$request]
if (eventPool) {
for (let i = 0; i< eventPool.length; i++) {
if (eventPool[i].cb) eventPool[i].cb(params)
if (eventPool[i].once) {
eventPool.splice(i, 1)
i--
}
}
}
}
const listen = function () {
const addEventListener = window.addEventListener || window.attachEvent
const type = window.addEventListener ? 'message' : 'onmessage'
addEventListener(type, (event) => {
// 不处理非目标源请求
if (event.origin !== this.targetOrigin && this.targetOrigin !== '*') return
const { data: { $type, $request, params } } = event
switch ($type) {
case 'emit': {
handleEmit.call(this, { $request, params })
break
}
default:
}
}, false)
}
class PostMessage {
constructor (targetOrigin = '*', targetWindow = window.parent) {
debugger
this.targetOrigin = targetOrigin
this.targetWindow = () => typeof targetWindow === 'function' ? targetWindow() : targetWindow
this.eventPool = {}
listen.call(this)
}
emit (event, params) {
const payload = { $request: event, $type: 'emit', params }
this.targetWindow().postMessage(payload, this.targetOrigin)
}
on (event, cb) {
const $uuid = uuid()
if (!this.eventPool[event]) this.eventPool[event] = []
if (cb) this.eventPool[event].push({ cb, $uuid })
return $uuid
}
off (event, eventId) {
if (!eventId) {
delete this.eventPool[event]
} else if (this.eventPool[event]) {
const eventIndex = this.eventPool[event].findIndex(item => item.$uuid === eventId)
if (eventIndex !== -1) this.eventPool[event].splice(eventIndex, 1)
}
}
once (event, cb) {
const $uuid = uuid()
if (!this.eventPool[event]) this.eventPool[event] = []
if (cb) this.eventPool[event].push({ cb, $uuid, once: true })
}
}
</script>
<script>
var innerWindow = document.querySelector('#iframe').contentWindow
console.log(document.querySelector('#iframe'))
console.log(innerWindow)
var codeWrapper = document.querySelector('#msg')
// 初始化
var PM = new PostMessage('*', innerWindow)
function handleSendMessage() {
// 发起testSendToInnerWindow事件
PM.emit('sendToInnerWindow', {
msg: Math.random().toString(36).substr(3).toLocaleUpperCase()
})
}
// 监听testSendToWrapper事件
PM.on('sendToWrapper', function (data) {
codeWrapper.innerHTML = data.text
})
</script>
</body>
</html>
iframe.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- <script src="../build/postMessage.js"></script> -->
<!-- <script src="../src/postMessage/index.js"></script> -->
<style>
.item{
margin: 10px 0;
}
</style>
</head>
<body>
<br>
<h3>常用方法</h3>
<fieldset class="item">
<legend>向上发起通知 [emit]</legend>
<button onclick="handleSendMessage()">发起通知</button>
发出的信息: <span id="sendMsg"></span>
</fieldset>
<fieldset class="item">
<legend>接收通知 [on]</legend>
接收的信息: <span id="receiveMsg"></span>
</fieldset>
<br>
<h3>非常用方法</h3>
<fieldset class="item">
<legend>每次执行只会监听一次, 适合特殊场景 [once]</legend>
<button onclick="startListenOnce()">开始监听</button>
接收的信息: <span id="receiveMsgOnce"></span>
</fieldset>
<fieldset class="item">
<legend>接收通知并可关闭监听 [off 有参]</legend>
<button onclick="stopListen()">停止监听</button>
接收的信息: <span id="receiveMsgAndStop"></span>
</fieldset>
<fieldset class="item">
<legend>关闭全部'sendToInnerWindow'事件监听 [off 无参]</legend>
<button onclick="stopAllListen()">停止全部监听</button>
</fieldset>
<script>
if (!Array.prototype.findIndex) {
Object.defineProperty(Array.prototype, 'findIndex', {
value: function (predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return k.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return k;
}
// e. Increase k by 1.
k++;
}
// 7. Return -1.
return -1;
}
});
}
const uuid = () => Math.random().toString(36).substr(2) + Date.now().toString(36)
const handleEmit = function ({ $request, params }) {
debugger
const eventPool = this.eventPool[$request]
if (eventPool) {
for (let i = 0; i< eventPool.length; i++) {
if (eventPool[i].cb) eventPool[i].cb(params)
if (eventPool[i].once) {
eventPool.splice(i, 1)
i--
}
}
}
}
const listen = function () {
debugger
const addEventListener = window.addEventListener || window.attachEvent
const type = window.addEventListener ? 'message' : 'onmessage'
addEventListener(type, (event) => {
// 不处理非目标源请求
if (event.origin !== this.targetOrigin && this.targetOrigin !== '*') return
const { data: { $type, $request, params } } = event
switch ($type) {
case 'emit': {
handleEmit.call(this, { $request, params })
break
}
default:
}
}, false)
}
class PostMessage {
constructor (targetOrigin = '*', targetWindow = window.parent) {
this.targetOrigin = targetOrigin
this.targetWindow = () => typeof targetWindow === 'function' ? targetWindow() : targetWindow
this.eventPool = {}
listen.call(this)
}
emit (event, params) {
debugger
const payload = { $request: event, $type: 'emit', params }
this.targetWindow().postMessage(payload, this.targetOrigin)
}
on (event, cb) {
const $uuid = uuid()
if (!this.eventPool[event]) this.eventPool[event] = []
if (cb) this.eventPool[event].push({ cb, $uuid })
return $uuid
}
off (event, eventId) {
if (!eventId) {
delete this.eventPool[event]
} else if (this.eventPool[event]) {
const eventIndex = this.eventPool[event].findIndex(item => item.$uuid === eventId)
if (eventIndex !== -1) this.eventPool[event].splice(eventIndex, 1)
}
}
once (event, cb) {
const $uuid = uuid()
if (!this.eventPool[event]) this.eventPool[event] = []
if (cb) this.eventPool[event].push({ cb, $uuid, once: true })
}
}
</script>
<script>
// 初始化 默认参数为 ('*', window.parent)
var PM = new PostMessage()
console.log('postMessage' + PM)
// 发送testSendToWrapper事件
function handleSendMessage() {
debugger
var info = Math.random().toString(36).substr(3).toLocaleUpperCase()
PM.emit('sendToWrapper', {
text: info
})
document.querySelector('#sendMsg').innerHTML = info
}
// sendToInnerWindow
var receiveMsg = document.querySelector('#receiveMsg')
PM.on('sendToInnerWindow', function(data) {
receiveMsg.innerHTML = data.msg
})
// sendToInnerWindow, 可独立处理
var receiveMsgAndStop = document.querySelector('#receiveMsgAndStop')
var testSendToInnerWindowId = PM.on('sendToInnerWindow', function(data) {
receiveMsgAndStop.innerHTML = data.msg
})
// 只监听一次
var receiveMsgOnce = document.querySelector('#receiveMsgOnce')
startListenOnce()
function startListenOnce() {
receiveMsgOnce.innerHTML = ''
PM.once('sendToInnerWindow', function(data) {
receiveMsgOnce.innerHTML = data.msg
})
}
// 关闭监听sendToInnerWindow off有ID参数
function stopListen() {
PM.off('sendToInnerWindow', testSendToInnerWindowId)
}
// 关闭全部sendToInnerWindow监听 off无ID参数
// !! 非sendToInnerWindow事件不受影响
function stopAllListen() {
PM.off('sendToInnerWindow')
}
</script>
</body>
</html>