微前端子应用间通信和数据共享

前面讲到了微前端的应用:(94条消息) 微前端应用(qiankun+umi+antd)_他夏了夏天吖的博客-CSDN博客https://blog.csdn.net/zh0623/article/details/130615234?spm=1001.2014.3001.5501今天具体讲一下父子应用的通信问题

主应用和子应用之间的通信和数据共享时,最常用的是自定义事件、消息总线、共享状态库或者通过事件订阅和发布、状态管理等方式来进行数据传递和同步.

1.自定义事件

主应用代码(React + TypeScript):

// 定义一个自定义事件名称
const customEventName = 'customEvent';

// 在主应用中订阅自定义事件
window.addEventListener(customEventName, (event: CustomEvent) => {
  // 处理自定义事件的数据
  const eventData = event.detail;
  console.log('Received event data in main app:', eventData);
});

// 在合适的时机发布自定义事件
const publishEvent = () => {
  const eventData = { message: 'Hello from sub app' };
  const event = new CustomEvent(customEventName, { detail: eventData });
  window.dispatchEvent(event);
};

子应用代码:

// 定义一个自定义事件名称
const customEventName = 'customEvent';

// 在子应用中订阅自定义事件
window.addEventListener(customEventName, (event) => {
  // 处理自定义事件的数据
  const eventData = event.detail;
  console.log('Received event data in sub app:', eventData);
});

// 在合适的时机发布自定义事件
const publishEvent = () => {
  const eventData = { message: 'Hello from main app' };
  const event = new CustomEvent(customEventName, { detail: eventData });
  window.dispatchEvent(event);
};

在上述示例中,主应用和子应用都定义了一个自定义事件名称,分别为 customEventName。主应用通过 window.addEventListener 方法监听该事件,并在事件处理函数中获取事件的数据。子应用通过 window.dispatchEvent 方法发布该事件,并传递相应的数据。

2. 消息总线

消息总线是一种更高级的跨应用通信方案,它允许不同的子应用之间通过消息队列来进行通信。在React和Vue中,我们可以使用第三方库(如PubSubJS)来实现消息总线。下面是一个简单的例子:在React中:

import React, { useState, useEffect } from 'react';
import PubSub from 'pubsub-js';

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const token = PubSub.subscribe('increment', (msg, data) => {
      setCount(data.count);
    });

    return () => {
      PubSub.unsubscribe(token);
    };
  }, []);

  function handleClick() {
    PubSub.publish('increment', { count: count + 1 });
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

export default App;

在Vue中:

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="handleClick">Increment</button>
  </div>
</template>

<script>
import PubSub from 'pubsub-js';

export default {
  data() {
    return {
      count: 0,
    };
  },
  mounted() {
    PubSub.subscribe('increment', (msg, data) => {
      this.count = data.count;
    });
  },
  methods: {
    handleClick() {
      PubSub.publish('increment', { count: this.count + 1 });
    },
  },
};
</script>

在上面的例子中,我们在React和Vue中都使用了PubSubJS库来实现消息总线。当用户点击“Increment”按钮时,我们会发布一个名为“increment”的消息,并将当前计数器的值作为消息的详细信息传递给其他子应用。同时,我们还在组件中订阅了“increment”消息,并在收到消息时更新计数器的值。

除了上面的方式,消息总线还有以下几种方式:

1. 本地事件总线:使用事件监听和事件触发在同一个应用内部通信。
2. 跨窗口消息传递:使用 postMessage 在不同的浏览器窗口/标签页之间通信。
3. Web Sockets:使用 WebSocket 协议在客户端和服务器之间建立持久连接,进行双向通信。
4. 本地存储事件:使用本地存储监听 storage 事件在不同的浏览器窗口/标签页之间通信。
5. 第三方消息代理:使用第三方服务如 Pusher、Socket.io 等在客户端之间传递消息。

2.1 本地事件总线

React 项目:

js
// React 项目
import { useState } from 'react';

// 创建事件总线
const eventBus = {
  on(event, callback) {
    document.addEventListener(event, callback);
  },
  emit(event, data) {
    document.dispatchEvent(new CustomEvent(event, { detail: data })); 
  } 
}

function ReactApp() {
  const [msg, setMsg] = useState('');
  
  // 监听事件
  useEffect(() => {
    eventBus.on('message', (e) => {
      setMsg(e.detail); 
    })
  }, []);
  
  return <div>{msg}</div>  
}

Vue项目:

js
// Vue 项目

// 创建事件总线
const eventBus = new Vue(); 

methods: {
  sendMessage() {
    eventBus.$emit('message', 'Hello from Vue!'); 
  }
},
mounted() {
  eventBus.$on('message', (msg) => {
    this.msg = msg; 
  });
}

2.2 跨窗口消息传递postMessage

//React:
js
// 发送消息
window.opener.postMessage('Hello from React!', '*');

// 接收消息
window.addEventListener('message', (e) => {
  console.log(e.data); // Hello from Vue!
});
//Vue:
js
// 发送消息
window.opener.postMessage('Hello from Vue!', '*');

// 接收消息
window.addEventListener('message', (e) => {
  console.log(e.data); // Hello from React!
});

3. Web Sockets进行双向通信

js
// React 项目
import { useState, useEffect } from 'react';

function ReactApp() {
  const [msg, setMsg] = useState('');
  
  // 连接 WebSocket 
  useEffect(() => {
    const socket = new WebSocket('ws://localhost:3000');
    socket.onmessage = (e) => {
      setMsg(e.data); 
    }
  }, []);
  
  return <div>{msg}</div>  
}

// Vue 项目
methods: {
  sendMessage() {
    this.$socket.send('Hello from Vue!');
  }
},
sockets: {
  connect() {
    this.$socket = new WebSocket('ws://localhost:3000');
  }  
}


4. 本地存储事件:使用本地存储监听 storage 事件在不同的浏览器窗口/标签页之间通信

//React:
js
// 发送消息
localStorage.setItem('message', 'Hello from React!');

// 接收消息
window.addEventListener('storage', (e) => {
  console.log(e.newValue); // Hello from Vue!
}); 
/Vue:
js
// 发送消息 
localStorage.setItem('message', 'Hello from Vue!');

// 接收消息
window.addEventListener('storage', (e) => {
  console.log(e.newValue); // Hello from React!
});


5. 第三方消息代理:使用第三方服务如 Pusher、Socket.io 等在客户端之间传递消息

//Socket.io:
//React:
js
// 连接 Socket.io
const socket = io('http://localhost:4000');

// 发送消息
socket.emit('message', 'Hello from React!'); 

// 接收消息
socket.on('message', (msg) => {
  console.log(msg); // Hello from Vue!
});
//Vue:
js
// 连接 Socket.io
const socket = io('http://localhost:4000');

// 发送消息
socket.emit('message', 'Hello from Vue!');

// 接收消息
socket.on('message', (msg) => {
  console.log(msg); // Hello from React!
});
//Socket.io 服务器:
//js
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);

io.on('connection', (socket) => {
  socket.on('message', (msg) => {
    socket.broadcast.emit('message', msg);
  });  
});

http.listen(4000);

3.共享状态库

//在React中:javascript
import React from 'react';
import { createStore } from 'redux';

const initialState = { count: 0 };

function reducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    default:
      return state;
  }
}

const store = createStore(reducer);

function App() {
  const { count } = store.getState();

  function handleClick() {
    store.dispatch({ type: 'INCREMENT' });
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

export default App;
//在Vue中:javascript
<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="handleClick">Increment</button>
  </div>
</template>

<script>
import { mapState, mapActions } from 'vuex';

export default {
  computed: mapState(['count']),
  methods: mapActions(['increment']),
};
</script>

在微前端中,不同的子应用之间可以通过多种方式进行通信和数据共享,不仅限于引用组件的方式。下面是一些常见的场景和解决方案:

1. 引用组件的方式在主应用中引用不同子应用的组件时,可以使用上面提到的自定义事件、消息总线或共享状态库等方式进行通信和数据共享。这种方式通常适用于子应用以组件的形式嵌入到主应用中的场景。

2. 路由的方式如果不同的子应用是通过路由的方式在主应用中引用的,可以使用URL参数、localStorage或cookie等方式进行通信和数据共享。例如,我们可以在URL参数中传递一些数据,或者使用localStorage或cookie来存储一些共享状态。

3. 独立运行的方式如果不同的子应用是独立运行的,它们之间无法直接进行通信和数据共享。但是,我们可以使用一些第三方工具或技术来实现跨域通信和数据共享,例如iframe、postMessage、WebSocket等。总之,不同的场景和需求需要选择不同的通信和数据共享方案。在实际应用中,我们需要根据具体情况来选择最合适的方案。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值