Appearance
封装 mitt.js
mitt 是什么
简单的说 mitt 就是一个全局的总线程,在 vue2.0 中,我们经常会使用EventBus去处理问题,这时候你会说啥是总线程呢。更简单的说,其实就是发布订阅事件。
EventBus 的简易源码
javascript
class Bus {
constructor() {
this.callback = {};
}
/**
* @description: 发布事件
* @param {*} name 名称
* @param {*} fn 方法
*/
$on(name, fn) {
this.callback[name] = this.callback[name] || [];
this.callback[name].push(fn);
}
/**
* @description: 订阅器-接收器
* @param {*} name 方法的名称
* @param {*} args 入参
*/
$emit(name, args) {
if (this.callback[name]) {
this.callback[name].forEach((cb) => {
cb(args);
});
}
}
}
// 挂载在 vue 的原型上
Vue.prototype.$bus = new Bus();
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
27
28
29
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
27
28
29
miit 的使用
安装
npm install --save mitt
1
通常的使用
javascript
import mitt from "mitt";
const emitter = mitt();
const TOPIC = "topic";
// 订阅
emitter.on(TOPIC, (data) => {
console.log(data);
});
// 发布事件
emitter.emit(TOPIC, { a: "b" });
// 取消订阅
emitter.off(TOPIC, onFoo);
// 清空所有的事件
emitter.all.clear();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
问题与痛点
命名问题
每一次都需要去思考不重名,一旦使用重名,将很难定位问题
销毁事件
事件都挂载到了总线程上,你需要思考如何去销毁掉订阅的事件,避免不必要的开销
为什么不去用 store 去处理问题
所有的问题存在则是必然,可为什么是必然呢?做一个假设,你现在处理一个表格数据的刷新,你是希望把表格数据放在 store 中还是放在业务组件中吗?很显然业务组件中,可以让代码的逻辑更加要区分,而不是把所有的数据,一股脑的放入 store 处理,这样代码的单一职责原则才能更好的体现。
hook 封装
useEventbus.ts
typescript
import { onUnmounted } from "vue";
import mitt from "mitt";
type IUseEventbus = {
customEmit: (eventName: string) => void;
customOn: (eventName: string, callback: () => void) => void;
toRefreshTable: () => void;
refreshTable: (callback: () => void) => void;
};
const emitter: mitt.Emitter = mitt();
/**
* @description: 自定义触发器
* @param {*} eventName 名称
*/
const customEmit = (eventName: string) => {
emitter.emit(eventName);
};
/**
* @description: 自定义接收器
* @param {*} name 名称
* @param {*} callback 回调的函数
*/
const customOn = (eventName: string, callback: () => void) => {
emitter.on(eventName, () => callback());
};
/**
* @description: 通知刷新表格数据
*/
const toRefreshTable = () => {
emitter.emit("refreshTable");
};
/**
* @description: 刷新表格数据
* @param {*} callback 回调的函数
*/
const refreshTable = (callback: () => void) => {
emitter.on("refreshTable", () => callback());
};
/**
* @description: 导出useEventbus
*/
export const useEventbus = (): IUseEventbus => {
// 销毁的事件
onUnmounted(() => {
// 清空所有的事件,避免多组件互相清理
emitter.all.clear();
});
return {
customEmit,
customOn,
toRefreshTable,
refreshTable,
};
};
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
main.vue - 主组件
html
<script lang="ts" setup>
import { onMounted } from "vue";
import { useEventbus } from "@/hooks/useEventbus";
const eventbus = useEventbus();
onMounted(() => {
// 订阅 init 方法
eventbus.customOn("init", () => {
init();
});
});
const init = () => {
// http
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
release.vue - 发布通讯组件
html
<script lang="ts" setup>
import { useEventbus } from "@/hooks/useEventbus";
const eventbus = useEventbus();
const handleClick = () => {
// 发布通讯
eventbus.customEmit("init");
};
</script>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10