在vue中使用事件
// 例子1:
// parent 接收
this.$on('test', function (msg) {
console.log(msg) // hi
})
// children 传出
this.$emit('test', 'hi')
// 例子2:
// 父组件监听子组件传出事件
<my-component v-hook:created="dosomething"></my-component>
// 例子3:
// 一次监听回调后销毁监听
<my-component v-on:click.once="dosomething"></my-component>
上面的代码是vue的标准事件监听然后接收使用,一般用于父子组件通讯。
而在vue源码里面,是怎么实现这个功能呢?
在vue初始化过程中,事件的初始化在初始化生命周期(initLifecycle)后。
所有关于组件事件的都会在此被在此被收集记录
注: 本章对于dom事件的绑定不作解析,源码对于dom事件在render流程中,故后面render中作讲解
初始化
首先来看初始化方法
/*初始化事件*/
export function initEvents(vm: Component) {
/*在vm上创建一个_events对象,用来存放事件。*/
vm._events = Object.create(null);
/*这个bool标志位来表明是否存在钩子,而不需要通过哈希表的方法来查找是否有钩子,这样做可以减少不必要的开销,优化性能。*/
// 比如: v-hook:created="dosomething"
vm._hasHookEvent = false;
// init parent attached events
/*初始化父组件attach的事件*/
const listeners = vm.$options._parentListeners;
if (listeners) {
updateComponentListeners(vm, listeners);
}
}
Object.create(null): 传建一个原型指向null的对象,它和 new object 还有 {} 对比的好处是,创建出来的对象原型没有Object附带的各种属性方法,可以减少副作用,MDN Object.create()
parentListeners: 此变量在父组件初始化子组件前,会在options加入此变量,代表父组件的监听事件
事件的添加监听以及取消监听
在events.js里面,定义了add、remove两个函数用于添加监听、取消监听,而这两个函数也只是很简单的调用用原型方法的$on、$off、$once来达到监听的效果
let target: Component;
/*有once的时候注册一个只会触发一次的方法,没有once的时候注册一个事件方法*/
function add(event, fn, once) {
if (once) {
target.$once(event, fn);
} else {
target.$on(event, fn);
}
}
/*销毁一个事件方法*/
function remove(event, fn) {
target.$off(event, fn);
}
/*更新组件的监听事件*/
export function updateComponentListeners(vm: Component, listeners: Object, oldListeners: ?Object) {
target = vm;
// listeners 父on 事件
// oldListeners 旧的On事件,初始化时为空
updateListeners(listeners, oldListeners || {
}, add, remove, vm);
}
$on、$off、$emit、$once原型方法
在events.js文件中,在vue的原型中挂载了 $on、$off、$emit、$once这四个方法,上面的添加监听以及取消监听就是运行了这四个函数的三个进行添加监听以及取消监听。
下面方法的代码都比较简单,里面都有注释,就不单独提出来讲。
方法 | 在vue中作用 |
---|---|
$on | 监听子组件的事件 |
$once | 监听子组件的事件,触发一次并取消监听 |
$off | 取消监听事件 |
$emit |