首页 > 编程笔记 > JavaScript笔记
阅读:18
Vue mitt库实现组件通信(附带实例)
在 Vue 中,利用第三方类库 mitt 可以实现非父子之间的通信。
执行下方命令,在当前项目中安装依赖:
src/services/emitter.js 文件代码如下:
假如在父组件 App 中有两个子组件 Child1 和 Child2,我们不想通过父组件 App 来实现两个子组件之间的通信,而是希望直接使两个子组件之间产生通信。这其实就是非父子之间通信的一种方式,按照这两个子组件的关系,其属于兄弟组件。
按照上面需求的描述,App 组件只是对两个子组件进行引入,不存在属性传递和事件监听,那么 App.vue 文件代码就很简单了,具体如下:
在 Child2 中我们就可以利用 emitter 对象的 emit() 方法来分发事件,并指定一个特定的要增加的数量。
components/Child2.vue 文件代码如下:
而 Child1 要利用 emitter 对象绑定自定义事件,指定接收数据的回调函数,在回调函数中更新要显示的 count 数值,并且需要在合适的时机取消绑定的事件。
components/Child1.vue 文件代码如下:
值得一提的是,我们通常会在组件实例完全销毁前(onBeforeUnmount 生命周期钩子函数),利用 emitter 对象的 off() 方法对绑定的事件进行取消。
此时可以利用 Child2 中的按钮来修改 Child1 中的 count 值,轻松实现非父子组件之间的通信。但这种通信方式在组件数量越来越多、需求越来越多的情况下,代码会被分散在不同的组件中,组件的通信关系会变得越来越混乱和繁杂,甚至形成蜘蛛网结构,管理起来并不方便。
对于这种情况,我们可以考虑通过 Vuex 和 Pinia 状态管理器解决。
执行下方命令,在当前项目中安装依赖:
npm install mitt -save安装依赖后,需要在当前项目中引入并创建进行事件处理的 emitter 对象。在 src 目录下创建 services 目录,并在其中创建 emitter.js 文件,在该文件中只需要引入 mitt 类库,得到其暴露的 mitt() 函数,执行 mitt() 函数产生 emitter 对象,并对其进行默认暴露。
src/services/emitter.js 文件代码如下:
import mitt from 'mitt'; export default mitt();emitter 对象主要提供了 on()、emit()、off()、all() 这 4 个方法,可以利用 on() 方法监听自定义事件,利用 emit() 方法分发自定义事件,利用 off() 方法取消特定自定义事件,以及利用 all() 方法取消所有事件。
假如在父组件 App 中有两个子组件 Child1 和 Child2,我们不想通过父组件 App 来实现两个子组件之间的通信,而是希望直接使两个子组件之间产生通信。这其实就是非父子之间通信的一种方式,按照这两个子组件的关系,其属于兄弟组件。
按照上面需求的描述,App 组件只是对两个子组件进行引入,不存在属性传递和事件监听,那么 App.vue 文件代码就很简单了,具体如下:
<script setup> import Child1 from './components/Child1.vue'; import Child2 from './components/Child2.vue'; </script> <template> <Child1 /> <Child2 /> </template>假如我们要实现 Child2 向 Child1 发送一个数值,Child1 收到这个数值后,累加显示到原有的 count 数值上。
在 Child2 中我们就可以利用 emitter 对象的 emit() 方法来分发事件,并指定一个特定的要增加的数量。
components/Child2.vue 文件代码如下:
<template> <div> <h1>Child2</h1> <button @click="increase">increase</button> </div> </template> <script setup> import emitter from '../services/emitter'; // 引入事件总线 // 在组件内部分发事件 const increase = () => { emitter.emit('increaseCount', 2); }; </script>在按钮的点击回调中,通过 emitter 对象的 emit() 方法分发了自定义事件 increaseCount,并指定了要传递的数量为 2。
而 Child1 要利用 emitter 对象绑定自定义事件,指定接收数据的回调函数,在回调函数中更新要显示的 count 数值,并且需要在合适的时机取消绑定的事件。
components/Child1.vue 文件代码如下:
<template> <div> <h1>Child1</h1> <p>count:{{ count }}</p> </div> </template> <script setup> import { ref, onMounted, onBeforeUnmount } from 'vue'; import emitter from '../services/emitter'; // 引入事件总线 const count = ref(0); // 绑定事件的回调函数,接收事件参数并进行使用 const increaseCountCallback = (num) => { count.value += num; }; // 在组件实例挂载完成时,订阅事件 onMounted(() => { emitter.on('increaseCount', increaseCountCallback); }); // 在组件实例完全销毁前,取消订阅事件 onBeforeUnmount(() => { emitter.off('increaseCount', increaseCountCallback); }); </script>上面的代码在 onMounted 挂载完成的生命周期钩子函数中绑定了自定义事件,事件名为子组件 Child2 中的 increaseCount,事件的回调函数接收的参数 num 是分发事件时传递的数据,在回调函数中将其累加到 count 中。
值得一提的是,我们通常会在组件实例完全销毁前(onBeforeUnmount 生命周期钩子函数),利用 emitter 对象的 off() 方法对绑定的事件进行取消。
此时可以利用 Child2 中的按钮来修改 Child1 中的 count 值,轻松实现非父子组件之间的通信。但这种通信方式在组件数量越来越多、需求越来越多的情况下,代码会被分散在不同的组件中,组件的通信关系会变得越来越混乱和繁杂,甚至形成蜘蛛网结构,管理起来并不方便。
对于这种情况,我们可以考虑通过 Vuex 和 Pinia 状态管理器解决。