qiankun 微前端框架子应用间通信方法详解

qiankun 作为流行的微前端解决方案,提供了多种子应用间通信的方式。以下是全面的通信方法总结:

1. 基于 props 的通信(主应用与子应用)

主应用向子应用传递数据

javascript 复制代码
// 主应用注册子应用时传递数据
registerMicroApps([
  {
    name: 'subApp',
    entry: '//localhost:7100',
    container: '#subapp-container',
    activeRule: '/sub-app',
    props: {  // 通过props传递数据
      basePath: '/sub-app',
      globalState: mainAppState,
      onStateChange: (state) => { /* 回调函数 */ }
    }
  }
]);

子应用接收数据

javascript 复制代码
// 子应用入口文件
export async function mount(props) {
  console.log(props.basePath); // 使用主应用传递的数据
  props.onGlobalStateChange((state, prevState) => {
    // 监听全局状态变化
  });
}

2. 全局状态管理(推荐方式)

使用 qiankun 的 initGlobalState

主应用初始化全局状态

javascript 复制代码
// 主应用
import { initGlobalState } from 'qiankun';

const initialState = { user: { name: 'Admin' } };
const actions = initGlobalState(initialState);

// 监听状态变化
actions.onGlobalStateChange((state, prev) => {
  console.log('主应用观察到的状态变化:', state, prev);
});

// 设置状态
actions.setGlobalState({ ...initialState, menu: ['home'] });

子应用使用全局状态

javascript 复制代码
// 子应用
export function mount(props) {
  // 监听全局状态
  props.onGlobalStateChange((state, prev) => {
    console.log('子应用收到的状态:', state);
  }, true); // 第二个参数为是否立即触发
  
  // 更新全局状态
  props.setGlobalState({ user: { name: 'SubAppUser' } });
}

3. 自定义事件通信(EventBus 模式)

创建全局事件总线

javascript 复制代码
// 主应用或公共文件
class EventBus {
  constructor() {
    this.events = {};
  }
  
  $on(event, callback) {
    if (!this.events[event]) this.events[event] = [];
    this.events[event].push(callback);
  }
  
  $emit(event, ...args) {
    (this.events[event] || []).forEach(cb => cb(...args));
  }
}

// 挂载到全局
window.microFrontendEventBus = new EventBus();

子应用间通信

javascript 复制代码
// 应用A发送事件
window.microFrontendEventBus.$emit('data-shared', { key: 'value' });

// 应用B监听事件
window.microFrontendEventBus.$on('data-shared', (data) => {
  console.log('收到数据:', data);
});

4. 使用 Redux/Vuex 等状态管理库

共享 store 方案

javascript 复制代码
// 主应用创建store并传递给子应用
const store = createStore(reducer, initialState);
registerMicroApps([{
  name: 'subApp',
  entry: '//localhost:7100',
  props: { store }
}]);

// 子应用使用
export function mount({ store }) {
  store.subscribe(() => {
    console.log('状态变化:', store.getState());
  });
  store.dispatch({ type: 'UPDATE', payload: {} });
}

5. localStorage/sessionStorage 通信

javascript 复制代码
// 应用A设置数据
localStorage.setItem('shared-data', JSON.stringify({ key: 'value' }));

// 应用B监听变化
window.addEventListener('storage', (event) => {
  if (event.key === 'shared-data') {
    console.log('数据已更新:', JSON.parse(event.newValue));
  }
});

6. 使用 window 全局变量

javascript 复制代码
// 主应用设置全局对象
window.__MAIN_APP_STATE__ = { 
  token: 'abc123',
  updateToken: (newToken) => { /* ... */ }
};

// 子应用访问
const token = window.__MAIN_APP_STATE__.token;
window.__MAIN_APP_STATE__.updateToken('newToken');

7. 使用 BroadcastChannel API(跨标签页通信)

javascript 复制代码
// 所有应用中使用相同的channel名称
const channel = new BroadcastChannel('micro-frontend-channel');

// 发送消息
channel.postMessage({ type: 'DATA_UPDATE', payload: {} });

// 接收消息
channel.onmessage = (event) => {
  console.log('收到消息:', event.data);
};

8. 使用 postMessage(iframe 式通信)

主应用与子应用通信

javascript 复制代码
// 主应用发送消息
window.postMessage({ type: 'FROM_MAIN', data: {} }, '*');

// 子应用接收
window.addEventListener('message', (event) => {
  if (event.data.type === 'FROM_MAIN') {
    console.log(event.data.data);
  }
});

最佳实践建议

  1. 简单场景 :使用 qiankun 内置的 initGlobalState 即可满足需求
  2. 复杂场景:推荐组合使用全局状态管理 + 自定义事件
  3. 安全考虑
    • 避免直接暴露修改全局状态的方法
    • 对通信数据进行校验
    • 使用命名空间避免冲突(如 __MAIN_APP__ 前缀)
  4. 性能优化
    • 避免高频通信
    • 对大体积数据考虑使用共享存储
  5. 类型安全(TypeScript 项目):
typescript 复制代码
// 定义全局状态类型
interface GlobalState {
  user: {
    name: string;
    role: string;
  };
  token?: string;
}

// 安全访问全局状态
if (window.__POWERED_BY_QIANKUN__) {
  const state = (props as { getGlobalState: () => GlobalState }).getGlobalState();
}

通信方式对比

方法 适用场景 优点 缺点
props 传递 主-子单向通信 简单直接 只能主传子,不能子传子
initGlobalState 任意应用间通信 官方推荐,内置支持 需要手动管理状态变更
自定义事件 任意应用间通信 灵活,解耦 需要自己实现事件管理
全局状态管理 复杂状态共享 专业状态管理 增加复杂度
localStorage 持久化数据共享 简单,跨标签页 数据类型受限,安全性问题
window 全局变量 简单数据共享 非常直接 容易造成污染,不安全
BroadcastChannel 跨标签页通信 原生支持,高效 兼容性考虑
postMessage iframe 式隔离环境 安全隔离 使用较复杂

选择通信方式时,应根据项目复杂度、团队技术栈和安全要求综合评估。对于大多数 qiankun 项目,组合使用 initGlobalState 和自定义事件通常是最佳选择。