接上篇 :01. 认识 Vue 对象(一)
今天我们接着来看 eventsMixin(Vue)
,这个方法给 Vue 赋予了如下功能:
Vue.prototype.$on
Vue.prototype.$emit
Vue.prototype.$once
Vue.prototype.$off
我们最熟悉的,当属 $on
和 $emit
了吧😀。
✨ $on
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
const vm: Component = this
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
if (hookRE.test(event)) {
vm._hasHookEvent = true
}
}
return vm
}
Vue 实例的事件是添加在 _events
属性上的,这个属性是一个对象,事件名称就是这个对象的键值,每个键的值是个数组。同时, Vue 为了优化性能,当实例接收了一个以 hook 开头的事件 时,会把 _hasHookEvent
设置为 true
。
_hasHookEvent
是一个用于提升性能的属性,作用是在调用生命周期钩子的时候,不用再遍历事件了。
✨ $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()
}
}
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++) {
try {
cbs[i].apply(vm, args)
} catch (e) {
handleError(e, vm, `event handler for "${event}"`)
}
}
}
return vm
}
这个方法里面,有两点需要注意:
-
第一个
if
的判断,是用于提示驼峰式 (camelCase) 或短横线分隔 (kebab-case)写法的,意思是:因为 HTML 是大小写不敏感的,所以你不能在 HTML 里使用驼峰写法。 -
toArray(list: any, start: number)
方法是将类数组(Array-like)对象转换成真正的数组对象。接受两个参数,第一个是待转换的对象,第二个用于截取。
✨ $off & $once
这两个方法都比较常规,代码 + API 一目了然。
❓ 遗留问题
-
this._events
是什么时候初始化的?
下一篇:03. 认识 Vue 对象(三)
网友评论