前言
vue2的vuex、和vue3的Pinia或者react的Redux,相信大家一定不陌生!在很多情况下,两个几乎不关联的组件之间通信,我们大多都会使用这些状态管理工具完成。
假设有下面的一个场景,我们需要再C组件点击一个按钮,请求一个数据,然后在发送给E组件,E组件执行一些逻辑处理。
如果我们的系统比较庞大,模块众多,选择Pinia是一个非常便捷的方式!但如果我们整个系统比较小,不同模块之间交互的情况不多,为了一个简单的功能引入Pinia是非常不划算的!
为了完成上面的需求,我们的代码必须这么写
首先,我们需要安装和设置Pinia,然后,我们创建一个 Pinia store 来管理数据。
// store.js
import {
createPinia } from 'pinia';
const pinia = createPinia();
export const useDataStore = pinia.store('data', {
state: () => ({
data: null,
}),
actions: {
fetchData() {
// 在这里发起接口请求获取数据,这里使用一个假的示例数据
const fakeData = '这是从接口获取的数据';
this.data = fakeData;
},
},
});
export default pinia;
接下来,我们创建 C 组件来触发数据请求。
<template>
<button @click="fetchData">请求数据</button>
</template>
<script>
import {
defineComponent } from 'vue';
import {
useDataStore } from './store';
export default defineComponent({
setup() {
const dataStore = useDataStore();
const fetchData = () => {
dataStore.fetchData();
};
return {
fetchData,
};
},
});
</script>
最后,我们创建 E 组件来接收数据并进行逻辑处理。
<template>
<div>
<p v-if="data">{
{
data }}</p>
<p v-else>暂无数据</p>
</div>
</template>
<script>
import {
defineComponent } from 'vue';
import {
useDataStore } from './store';
export default defineComponent({
setup() {
const dataStore = useDataStore();
// 从 store 中获取数据
const data = dataStore.data;
return {
data,
};
},
});
</script>
我们仅仅为了一个很小的功能,引入了Pinia,非常不划算!费事费力!
使用事件调度器优化代码
假设我们现在有个事件调度器,可以实现数据绑定与监听,它的用法是这样的
const dispatcher = new EventDispatcher()
// 绑定事件
dispatcher.addEventListener("patcher1",(res) => {
// 监听到的数据
console.log(res);
})
dispatcher.dispatchEvent('patcher1',"发送的数据")
我们用这个dispatcher优化上述的逻辑代码
/* C组件 */
<template>
<button @click="fetchData">请求数据</button>
</template>
<script setup>
const fetchData = () => {
dispatcher.dispatchEvent('patcher1',"发送的数据")
};
</script>
<template>
<div>
<p v-if="data">{
{
data }}</p>
<p v-else>暂无数据</p>
</div>
</template>
<script>
const data = ref("");
// 绑定事件
dispatcher.addEventListener("patcher1",(res) => {
// 监听到的数据
data.value = res
})
</script>
可以看到,同样的逻辑,我们使用dispatcher代码更加简洁!避免了引入pinia,不仅减少了代码体积,还让代码写起来更加简单!
可见,一些简单的场景,如整个系统之间只有个别组件之间存在交互,引入pinia或者redux等状态管理工具是非常不划算的!!
你可能会有疑惑,不是需要引入EventDispatcher这个类吗?这个类难道不复杂?体积不大?
事实上,这个类的代码也就十几行,完全可以手写,以后粘贴复制!
实现EventDispatcher事件调度器
我们这个EventDispatcher其实功能很简单,就是数据监听,数据绑定,移除事件三个功能。
它的使用方法应该如下
const dispatcher = new EventDispatcher()
// 绑定第一个一个事件
dispatcher.addEventListener("patcher1",(res) => {
// 监听到的数据
console.log(res);
})
// 绑定第二个事件
dispatcher.addEventListener("patcher2",(res) => {
// 监听到的数据
console.log(res);
})
// 触发第一个事件
dispatcher.dispatchEvent('patcher1',"发送的数据")
// 触发第二个事件
dispatcher.dispatchEvent('patcher2',"发送的数据")
//移除第一个事件
dispatcher.removeEventListener('patcher1')
//移除第二个事件
dispatcher.removeEventListener('patcher2')
要想实现这个功能,我们需要创建一个事件调度器EventDispatcher类,这个类的结构如下
export class EventDispatcher {
// 储存所有监听的事件
private listeners = {
};
// 绑定事件的方法
protected addEventListener(type: string, listener: Function) {
}
// 移除事件的方法
protected removeEventListener(type: string) {
}
// 触发事件的方法
protected dispatchEvent(type: string, data: any) {
}
}
我们完善其内部方法
export class EventDispatcher{
private listeners: {
[type: string]: Function[] } = {
};
protected addEventListener(type: string, listener: Function) {
if (!this.listeners[type]) {
this.listeners[type] = [];
}
if (this.listeners[type].indexOf(listener) === -1) {
this.listeners[type].push(listener);
}
}
protected removeEventListener(type: string) {
this.listeners[type] = [];
}
protected dispatchEvent(type: string, data: any) {
const listenerArray = this.listeners[type] || [];
if (listenerArray.length === 0) return;
listenerArray.forEach(listener => {
listener.call(this, data);
});
}
}
- listeners用于存储事件类型与对应监听器数组的映射。它是一个对象,键是事件类型(type),值是监听器函数数组。
- addEventListener用于添加事件监听器。它接受两个参数:事件类型(type)和监听器函数(listener)。如果当前事件类型尚未有对应的监听器数组,则创建一个空数组。然后,将传入的监听器函数添加到该数组中,但仅当该监听器函数不在数组中时才添加。
- dispatchEvent用于触发指定类型的事件,并传递相应的数据。它接受两个参数:事件类型(type)和要传递的数据(data)。首先,它从存储的监听器数组中获取与事件类型匹配的监听器数组。然后,遍历该数组,依次调用每个监听器函数,并传递数据作为参数。
- removeEventListener这是一个受保护的方法,用于移除指定类型的所有事件监听器。它接受一个参数:事件类型(type)。当调用该方法时,它会将指定类型的监听器数组清空。
上述代码实现了一个简单的事件调度器,它的核心原理是使用了一个对象 listeners 来存储事件类型和对应的监听器函数数组。当调用 addEventListener 方法添加监听器时,它会将监听器函数添加到对应事件类型的监听器数组中。当调用 dispatchEvent 方法触发事件时,它会获取对应事件类型的监听器数组,并依次调用每个监听器函数。而 removeEventListener 方法则用于移除指定类型的所有监听器。
如果你想在全局任意的地方使用这个数据调度器,我们只需要将它绑定在window对象上即可!
在我们的程序入口文件里进行挂载
const dispatcher = new EventDispatcher()
window.myDispatcher = dispatcher
现在,你可以在任何地方开心的使用这个方法了!简单的场景再也不用引入麻烦的pinia或者redux了!
总结
本教程中,基于简单业务不同组件之间交互的场景,我们使用手写的事件调度器EventDispatcher替代了pinia或者redux等状态管理工具,不仅简化了代码,还优化了项目体积,还让自己的代码更有逼格!相信大家看完一定有所收获!也欢迎大家能给出自己的建议,帮助他人哈!