因为对vue.js很感兴趣,而且平时工作的技术栈也是vue.js,这几个月花了些时间研究学习了一下vue.js源码,并做了总结与输出。本文主要介绍了vue.js源码之事件机制,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。
在学习过程中,为vue加上了中文的注释https://github.com/answershuto/learnvue/tree/master/vue-src,希望可以对其他想学习vue源码的小伙伴有所帮助。
可能会有理解存在偏差的地方,欢迎提issue指出,共同学习,共同进步。
vue事件api
众所周知,vue.js为我们提供了四个事件api,分别是$on](https://cn.vuejs.org/v2/api/#vm-on-event-callback),[$once,$off](https://cn.vuejs.org/v2/api/#vm-off-event-callback),[$emit。
初始化事件
初始化事件在vm上创建一个_events对象,用来存放事件。_events的内容如下:
{
eventname: [func1, func2, func3]
}
存放事件名以及对应执行方法。
/*初始化事件*/
export function initevents (vm: component) {
/*在vm上创建一个_events对象,用来存放事件。*/
vm._events = object.create(null)
/*这个bool标志位来表明是否存在钩子,而不需要通过哈希表的方法来查找是否有钩子,这样做可以减少不必要的开销,优化性能。*/
vm._hashookevent = false
// init parent attached events
/*初始化父组件attach的事件*/
const listeners = vm.$options._parentlisteners
if (listeners) {
updatecomponentlisteners(vm, listeners)
}
}
$on
$on方法用来在vm实例上监听一个自定义事件,该事件可用$emit触发。
vue.prototype.$on = function (event: string | array<string>, fn: function): component {
const vm: component = this
/*如果是数组的时候,则递归$on,为每一个成员都绑定上方法*/
if (array.isarray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.$on(event[i], fn)
}
} else {
(vm._events[event] || (vm._events[event] = [])).push(fn)
// optimize hook:event cost by using a boolean flag marked at registration
// instead of a hash lookup
/*这里在注册事件的时候标记bool值也就是个标志位来表明存在钩子,而不需要通过哈希表的方法来查找是否有钩子,这样做可以减少不必要的开销,优化性能。*/
if (hookre.test(event)) {
vm._hashookevent = true
}
}
return vm
}
$once
$once监听一个只能触发一次的事件,在触发以后会自动移除该事件。
vue.prototype.$once = function (event: string, fn: function): component {
const vm: component = this
function on () {
/*在第一次执行的时候将该事件销毁*/
vm.$off(event, on)
/*执行注册的方法*/
fn.apply(vm, arguments)
}
on.fn = fn
vm.$on(event, on)
return vm
}
$off
$off用来移除自定义事件
vue.prototype.$off = function (event?: string | array<string>, fn?: function): component {
const vm: component = this
// all
/*如果不传参数则注销所有事件*/
if (!arguments.length) {
vm._events = object.create(null)
return vm
}
// array of events
/*如果event是数组则递归注销事件*/
if (array.isarray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.$off(event[i], fn)
}
return vm
}
// specific event
const cbs = vm._events[event]
/*github:https://github.com/answershuto*/
/*本身不存在该事件则直接返回*/
if (!cbs) {
return vm
}
/*如果只传了event参数则注销该event方法下的所有方法*/
if (arguments.length === 1) {
vm._events[event] = null
return vm
}
// specific handler
/*遍历寻找对应方法并删除*/
let cb
let i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
return vm
}
$emit
$emit用来触发指定的自定义事件。
vue.prototype.$emit = function (event: string): component {
const vm: component = this
if (process.env.node_env !== 'production') {
const lowercaseevent = event.tolowercase()
if (lowercaseevent !== event && vm._events[lowercaseevent]) {
tip(
`event "${lowercaseevent}" is emitted in component ` +
`${formatcomponentname(vm)} but the handler is registered for "${event}". ` +
`note that html attributes are case-insensitive and you cannot use ` +
`v-on to listen to camelcase events when using in-dom templates. ` +
`you should probably use "${hyphenate(event)}" instead of "${event}".`
)
}
}
let cbs = vm._events[event]
if (cbs) {
/*将类数组的对象转换成数组*/
cbs = cbs.length > 1 ? toarray(cbs) : cbs
const args = toarray(arguments, 1)
/*遍历执行*/
for (let i = 0, l = cbs.length; i < l; i++) {
cbs[i].apply(vm, args)
}
}
return vm
}
相关推荐:
node事件机制解说
php事件机制的实现
jq与js中的事件机制与阻止
以上就是vue.js事件机制源码解析的详细内容。