先说一下 react/vue 的组件通信方式
- 父组件向子组件通信
- 子组件向父组件通信
- 跨级组件通信
- 非嵌套关系的组件通信
其中最后一种非嵌套的组件通信方式要怎么实现呢
- 如果是兄弟组件通信,可以找到这两个兄弟节点共同的父节点, 结合父子间通信方式进行通信。
- 可以通过 redux 等进行全局状态管理
- 可以使用自定义事件通信(发布订阅模式),使用 events.js
然后今天的主角就是他基于发布订阅模式实现的组建通信
什么是发布订阅模式呢?
在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。
发布订阅模式
结合 react 和 event.js 的使用来具体了解下。
首先有两个非嵌套关系的组件
全局新建 eventBus.js 文件,安装 event.js 后导出实例
这个时候实例相当于消息主体,负责存储消息与订阅者的对应关系,有消息触发时,负责通知订阅者。
1 2
| import { EventEmitter } from "events"; export default new EventEmitter();
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| import React from "react"; import ClassTest from "./ClassTest"; import FuncTest from "./FuncTest"; function App() { return ( <> <ClassTest /> <FuncTest /> </> ); }
export default App;
|
组件 ClassTest,这里的emitter.on('test')
就是相当于订阅者,去消息中心订阅自己感兴趣的消息。emitter.off('test')
取消订阅
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import React, { Component } from "react"; import emitter from "./eventbus";
class ClassTest extends Component { handleChange = (param1, param2) => { console.log(param1); console.log(param2); }; componentDidMount() { emitter.on("test", this.handleChange); } componentWillUnmount() { emitter.off("test", this.handleChange); } render() { return <div>class test</div>; } } export default ClassTest;
|
组件 FuncTestemitter.emit('test')
在这里是订阅者的身份,满足条件时,通过消息中心发布消息。此处的条件是点击这个 div
1 2 3 4 5 6 7 8 9 10
| import React, { useState, useContext } from "react"; import emitter from "./eventbus"; const FuncTest = () => { const handleChange = () => { emitter.emit("test", "参数1", "参数2"); }; return <div onClick={handleChange}>B组件</div>; };
export default FuncTest;
|
在点击这个 div 之后,通过事件总线将 emit 中携带的 “参数 1”, “参数 2”,传递到 on 的回调函数中。实现了组建的通信
在 vue 中也是类似,可以 new 一个 Vue 的实例,然后 vue 中提供了$on和$emit 等方法能达到同样的效果.
1
| export const EventBus = new Vue();
|
简单实现下我们只需在 emit 的时候触发 on 订阅的事件,并且将参数带过去。详细实现可以看注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function EventEmitter() { this.eventObj = {}; }
EventEmitter.prototype.on = function (event, callback) { this.eventObj[event] = this.eventObj[event] || []; this.eventObj[event].push(callback); };
EventEmitter.prototype.emit = function (event, ...args) { if (this.eventObj[event]) { this.eventObj[event].forEach((callback) => { callback(...args); }); } };
EventEmitter.prototype.off = function (event) { delete this.eventObj[event]; };
|
可以将上面的 eventbus.js 中引用的包替换为这个,看看是否正常运行。看到这里是不是豁然开朗呢,相信对 vue 中的 bus 总线或者是 event.js 一定有了更深的理解!