Vue $on $emit $off
文章简概
通过$on $emit $off 做事件中心,以及其手动实现。
常见的事件绑定例如$emit,在Vue的使用过程中,我们经常在子组件中通过$emit去调用父组件(容器)中的事件。
父组件
<div>
<child @doSomething="fatherMethod"/>
</div>
<script>
...
method: {
fatherMethod() {}
}
...
</script>
子组件
this.$emit('doSomething');
这是一种常见的简单应用,但是面对更多更复杂的场景,并不是显得那么好用,例如父组件下有AB两个子组件,而A组件想要触发B中的事件,则会有一些麻烦。
父组件
<div>
<child @doSomething="changeChild2Data"/>
<child2 :someData="someData"/>
</div>
<script>
...
method: {
changeChild2Data() {
// someData Change
}
}
...
</script>
子组件child2
...
watch: {
someData(newVal) {
// if value change
this.doSomethingNew();
}
}
...
可见,按照正常的流程会通过父组件做个中转,这样的操作徒增麻烦,同时在代码可读性及维护上带来了很多问题。但是通过Vue的 $on $emit $off 我们可以做一个事件中心(eventHub),对于这些事件做一个统一管理。
$on 可以将一个事件绑定。
$emit 触发绑定的事件
$off 对一个已绑定的事件解绑
Vue.prototype.eventHub = new Vue();
new Vue().$mount('#app')
在入口文件中我们将一个Vue插入到原型中的eventHub中,方便使用。
回到上面的场景,在子组件1中绑定事件,通过eventId标识
组件 Child
...
mounted() {
this.eventHub.$on('eventId', this.doSomethingNew)
}
...
在子组件2中触发事件,调用this.doSomethingNew()方法;
组件 Child2
...
method: {
dosomething() {
this.$eventHub.$emit('eventId');
}
}
...
通过$off 解绑对应的方法。
...
method: {
dosomething() {
this.$eventHub.$off('eventId');
}
}
...
通过上诉效果,简化了兄弟组件之间方法的调用过程。这就是事件中心的原理,通过一个事件中转站,对不同位置的事件进行一个统一的管理。从而提高了代码的可读性,简化了流程。
手动实现$on
const eventList = {};
const $on = function(eventId, myfun) {
if(!eventList[eventId]) {
eventList[eventId] = [];
}
eventList[eventId].push(myfun);
}
手动实现$emit
const $emit = function(eventId, data) {
if (eventList[eventId]) {
eventList[eventId].forEach(handle => handle(data));
}
}
手动实现$off
const $off = function(eventId, handle) {
const index = eventList[eventId].findIndex(fun=> fun===handle);
if (idnex > -1) {
eventList[eventId].splice(idnex, 1);
}
}
完整的eventHub手动实现
const createEventHub = () => ({
hub: Object.create(null),
emit(event, data) {
(this.hub[event] || []).forEach(handler => handler(data));
},
on(event, handler) {
if (!this.hub[event]) this.hub[event] = [];
this.hub[event].push(handler);
},
off(event, handler) {
const i = (this.hub[event] || []).findIndex(h => h === handler);
if (i > -1) this.hub[event].splice(i, 1);
}
});
参考文章:
https://www.html.cn/30-seconds-of-code/#createeventhub (30 秒就能理解的 JavaScript 代码片段)
https://vuejs.org (Vue官方文档)