PostMessageEmitter
基于 postMessage 实现的父子页面通讯中心
快速使用
Iframe嵌套
parent.html
<iframe name="ifr" src="./chilren.html" frameborder="0"></iframe>
let emitter = new PostMessageEmitter(ifr)
emitter.on("callFather" , (data)=>{
console.log(data) // "hello, i am children"
})
emitter.emit("callChildren" , "hello, i am father")
children.html
let emitter = new PostMessageEmitter(window)
emitter.on("callChildren" , (data)=>{
console.log(data) // "hello, i am father"
})
emitter.emit("callFather" , "hello, i am children")
window.open
parent.html
let emitter = new PostMessageEmitter(window.open(./chilren.html))
emitter.on("callFather" , (data)=>{
console.log(data) // "hello, i am children"
})
emitter.emit("callChildren" , "hello, i am father")
children.html
let emitter = new PostMessageEmitter(window)
emitter.on("callChildren" , (data)=>{
console.log(data) // "hello, i am father"
})
emitter.emit("callFather" , "hello, i am children")
特性
- 简单、统一的Api
- 支持一父多子
接口
interface IPostMessageEmiiter {
(el: Window | HTMLIFrameElement, domain: string): Emitter
on(eventName: string, cb: Function): void,
emit(eventName: string, data: any): void,
destroy(): void,
}
源码
function PostMessageEmitter(el, domain = "*") {
if (!(this instanceof PostMessageEmitter)) {
throw new TypeError("just support new invoke");
}
let currentWin = window;
let targetWin = null
let identity = null
if (currentWin === el) {
if (window.opener) {
targetWin = el.opener
} else {
targetWin = el.parent
}
identity = currentWin.identity
}
else if (el.tagName && el.tagName.toLowerCase() == "iframe" && el.contentWindow) {
targetWin = el.contentWindow;
targetWin.identity = identity = uuid()
}
else if (currentWin === el.opener) {
targetWin = el
targetWin.identity = identity = uuid()
}
if (!targetWin) {
throw new TypeError("argument[0] must be iframe or window");
}
let events = {};
const handleMessage = (e) => {
if (domain != "*" && e.origin !== domain) {
return;
}
let { type, data, _identity } = e.data || {};
if (identity !== _identity) {
return
}
let cbs = events[type] || [];
cbs.reduce((prev, cb) => {
cb && cb(prev);
return prev;
}, data);
};
window.addEventListener("message", handleMessage);
return {
emit(type, data) {
targetWin.postMessage(
{
type,
data,
_identity: identity
},
domain
);
},
on(type, cb) {
if (typeof cb != "function") {
throw new TypeError("argument[1] must a function!");
}
if (!events[type]) {
events[type] = [];
}
events[type].push(cb);
},
destroy() {
window.removeEventListener("message", handleMessage);
targetWin = null;
},
};
}
function uuid() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}