Skip to content

giszhc/iframe-client

Repository files navigation

Iframe Client

一个 简单、轻量、专注通信 的 JavaScript / TypeScript 库,用于 iframe 跨域消息传递

本库专注于 纯通信功能,不包含 iframe 创建和管理。用户需要自行创建 iframe,只需传入 window 对象即可开始通信。


✨ 特性

  • 🚀 轻量无依赖 - 仅专注于 postMessage 通信
  • 🔌 即插即用 - 支持传入 iframe DOM 或 window 对象
  • 🛡️ 类型安全 - 完整的 TypeScript 类型支持
  • 💬 双向通信 - 父页面与子页面自由对话
  • 🎯 安全验证 - 支持 origin + source 校验
  • 🤝 握手协议 - 内置 READY / ACK,确保通信可靠
  • 🧩 命名空间隔离 - 避免多实例/多应用消息冲突
  • 📦 简单易用 - API 简洁直观

在线示例

我们提供了一个功能完整的在线演示页面,您可以直接在浏览器中体验所有功能:

🌐 立即体验: 点击访问在线演示


安装

pnpm install @giszhc/iframe-client
#
npm install @giszhc/iframe-client
yarn add @giszhc/iframe-client

⚠️ 通信机制(重要)

本库内置 握手协议(Handshake),确保双方建立连接后再通信。

握手流程

child  → READY
parent → ACK
→ connected = true

使用原则

必须在 onConnect 后发送消息

const client = new IframeClient({
  type: 'parent',
  iframe,
  namespace: 'my-app:demo:v1',
  onConnect: () => {
    // ✅ 正确
    client.sendMessage('INIT', {});
  }
});

📦 消息结构

所有消息会被统一封装为:

{
  __iframe_client__: true,
  namespace: string,
  type: string,
  payload?: any
}

🚀 快速开始

父页面

import { IframeClient } from '@giszhc/iframe-client';

// 获取 iframe DOM 元素
const iframe = document.getElementById('myIframe') as HTMLIFrameElement;

const client = new IframeClient({
  type: 'parent',              // 指定当前角色为父页面
  iframe,                      // 传入 iframe DOM 元素
  targetOrigin: 'http://localhost:3001',  // 子页面的目标源地址(生产环境请指定具体域名)
  namespace: 'my-app:demo:v1', // 命名空间,用于消息隔离(格式建议:应用名:功能:版本)

  // 连接成功后的回调函数(握手完成后触发)
  onConnect: () => {
    console.log('✅ 已连接 iframe');

    // 发送初始化消息,包含用户 ID
    client.sendMessage('INIT', { id: 123 });
  }
});

// 监听来自子页面的 RESPONSE 类型消息
client.on('RESPONSE', (data) => {
  console.log('收到响应:', data);
});

子页面(iframe 内)

import { IframeClient } from '@giszhc/iframe-client';

const client = new IframeClient({
  type: 'child',               // 指定当前角色为子页面(iframe 内)
  targetWindow: window.parent, // 指定目标窗口为父窗口
  targetOrigin: 'http://localhost:3000',  // 父页面的源地址(生产环境请指定具体域名)
  namespace: 'my-app:demo:v1', // 命名空间,必须与父页面保持一致

  // 连接成功后的回调函数(握手完成后触发)
  onConnect: () => {
    console.log('✅ 已连接父页面');
  }
});

// 监听来自父页面的 INIT 类型消息
client.on('INIT', (data) => {
  console.log('收到:', data);

  // 发送响应消息给父页面
  client.sendMessage('RESPONSE', { ok: true });
});

API

配置

interface IframeClientConfig {
  type: 'parent' | 'child';
  iframe?: HTMLIFrameElement;
  targetWindow?: Window;
  targetOrigin?: string;
  namespace: string;
  onConnect?: () => void;
  onError?: (error: Error) => void;
}

sendMessage

client.sendMessage('EVENT', { data: 1 });

on

client.on('EVENT', (data, event) => {
  console.log(data);
});

off

client.off('EVENT', handler);

destroy

client.destroy();

isConnected

client.isConnected();

🔁 通信流程示例

【握手阶段】
child  → READY
parent → ACK

【业务通信】
parent → INIT
child  → RESPONSE

⚠️ 注意事项

1️⃣ 必须使用 namespace

// ❌ 错误
namespace: 'a'
namespace: 'b'

// ✅ 正确
namespace: 'my-app:demo:v1'

2️⃣ 不要提前发送消息

// ❌ 错误
client.sendMessage('INIT');

// ✅ 正确
onConnect: () => {
  client.sendMessage('INIT');
}

3️⃣ 必须传正确参数

// parent
new IframeClient({
  type: 'parent',
  iframe,
  namespace: 'xxx'
});

// child
new IframeClient({
  type: 'child',
  targetWindow: window.parent,
  namespace: 'xxx'
});

4️⃣ 生产环境不要用 '*'

targetOrigin: 'https://your-domain.com'

5️⃣ 记得销毁

client.destroy();

🔐 安全机制

  • origin 校验
  • source 校验
  • namespace 隔离
  • 内部消息标识过滤

❌ 常见错误

提前发送消息(会丢)

const client = new IframeClient({ ... });

client.sendMessage('INIT'); // ❌

namespace 不一致

👉 直接无法通信


FAQ

Q: onConnect 什么时候触发?

A: 在握手完成后触发(READY / ACK 完成)。


Q: payload 支持什么类型?

支持所有 结构化克隆数据

  • ✅ Object / Array
  • ✅ Map / Set
  • ✅ ArrayBuffer
  • ❌ Function / DOM

Q: 可以不用这个库吗?

可以,用原生:

window.postMessage(...)
window.addEventListener('message', ...)

但你需要自己处理:

  • 握手
  • 安全校验
  • 消息管理

📄 License

MIT


❤️ Made with ❤️


About

一个 简单、轻量、专注通信 的 JavaScript / TypeScript 库,用于 iframe 跨域消息传递。

Resources

Stars

Watchers

Forks

Releases

No releases published

Contributors