@ticatec/iframe-message-bridge
Version:
A lightweight TypeScript library for reliable communication between parent window and multiple iframes using postMessage, supporting one-way messages, request-response patterns, broadcast messaging, timeout handling, and automatic resource cleanup.
125 lines (124 loc) • 4.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageBridgeManager = void 0;
class MessageBridgeManager {
constructor() {
this.handlers = new Map();
this.broadcastHandlers = new Map();
this.boundHandleMessage = this.handleMessage.bind(this);
window.addEventListener('message', this.boundHandleMessage);
}
async handleMessage(event) {
const { data, source, origin } = event;
if (!data || data.__bridge__ !== true)
return;
// 处理请求-响应消息
if (data.type === 'request') {
const { requestId, eventName, data: requestData } = data;
const handler = this.handlers.get(eventName);
if (!handler)
return;
try {
const result = await handler(requestData, source, origin);
// 只有当 requestId 不为 null 时才发送响应
if (requestId !== null) {
const response = {
__bridge__: true,
type: 'response',
requestId,
result,
};
// @ts-ignore
source === null || source === void 0 ? void 0 : source.postMessage(response, origin);
}
}
catch (err) {
// 只有当 requestId 不为 null 时才发送错误响应
if (requestId !== null) {
const response = {
__bridge__: true,
type: 'response',
requestId,
error: err.message || String(err),
};
// @ts-ignore
source === null || source === void 0 ? void 0 : source.postMessage(response, origin);
}
}
}
// 处理广播消息
if (data.type === 'broadcast') {
const { eventName, data: broadcastData } = data;
const handler = this.broadcastHandlers.get(eventName);
if (handler) {
handler(broadcastData);
}
}
}
// 原有的请求-响应处理器注册
on(eventName, handler) {
this.handlers.set(eventName, handler);
}
// 注册广播消息处理器
onBroadcast(eventName, handler) {
this.broadcastHandlers.set(eventName, handler);
}
// 注销请求-响应处理器
off(eventName) {
this.handlers.delete(eventName);
}
// 注销广播消息处理器
offBroadcast(eventName) {
this.broadcastHandlers.delete(eventName);
}
// 清空所有请求-响应处理器
clearHandlers() {
this.handlers.clear();
}
// 清空所有广播消息处理器
clearBroadcastHandlers() {
this.broadcastHandlers.clear();
}
// 销毁实例,移除全局监听器
destroy() {
window.removeEventListener('message', this.boundHandleMessage);
this.handlers.clear();
this.broadcastHandlers.clear();
}
// 自动获取所有iframe窗口
getAllIframes() {
const iframes = document.querySelectorAll('iframe');
const iframeWindows = [];
iframes.forEach(iframe => {
try {
if (iframe.contentWindow) {
iframeWindows.push(iframe.contentWindow);
}
}
catch (error) {
// 跨域iframe可能无法访问contentWindow,但仍可以发送消息
console.warn('Cannot access iframe contentWindow (may be cross-origin):', error);
}
});
return iframeWindows;
}
// 向所有iframe广播消息
broadcast(eventName, data, targetOrigin = '*') {
const message = {
__bridge__: true,
type: 'broadcast',
eventName,
data,
};
const iframeWindows = this.getAllIframes();
iframeWindows.forEach(iframeWindow => {
try {
iframeWindow.postMessage(message, targetOrigin);
}
catch (error) {
console.warn('Failed to send broadcast message to iframe:', error);
}
});
}
}
exports.MessageBridgeManager = MessageBridgeManager;