This function mainly mounts custom events “on”, “on”, “on”, “once”, “off”, “off”, “off”, “emit” on vue’s “Prototype” object.
Let’s look at the code of these functions in detail:
$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++) {
vm.$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
}
Copy the code
As you can see, $on takes two parameters, event and fn, which are the event name and event handler respectively. The event name can be an array, which means that different events are bound to the same event handler.
(vm._events[event] || (vm._events[event] = [])).push(fn)
Copy the code
If you look at the above line of code, you can see that defining duplicate event names is separate and will not be combined into one event.
// const hookRE = /^hook:/
if (hookRE.test(event)) {
vm._hasHookEvent = true
}
Copy the code
This line of code sets the _hasHookEvent variable to true when your event name starts with hook:. I’m going to call this a hook event, which means that when a lifecycle hook is called, it triggers the corresponding hook event, For example, (on(‘hook:created’, fn), on(‘hook:created’, FN), on(‘hook:created’, FN), on(‘ Hook :mounted’, FN)).
$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
}
Copy the code
$on = $emit; $on = $emit; $on = $emit; $on = $emit; $on = $emit; And call apply to change this, which is equivalent to whether fn is an arrow function or not.
$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 if (Array.isArray(event)) { for (let i = 0, l = event.length; i < l; i++) { vm.$off(event[i], fn) } return vm } // specific event const cbs = vm._events[event] if (! cbs) { return vm } if (! fn) { 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 }Copy the code
As you can see, $off also takes two parameters, but both are optional. First check to see if there are any arguments, and if they are useful, set _events to null, which clears all events. Then check whether the event is an array and recursively call $off.
if (! cbs) { return vm }Copy the code
If the event name does not exist, return VM is no longer executed.
if (! fn) { vm._events[event] = null return vm }Copy the code
If the FN event does not exist, all listeners for that event are removed.
let cb
let i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
Copy the code
If the fn argument is equal to cb, or to cb.fn, it is removed from the array.
$cb.fn = on. Fn = fn
$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 // processes the second argument to the $emit function, Arguments [1] const args = toArray(arguments, 1) const info = 'event handler' for "${event}" 'for (let I = 0, l = cbs.length; i < l; i++) { invokeWithErrorHandling(cbs[i], vm, args, vm, info) } } return vm }Copy the code
If the event name is lowerCaseEvent and the event handler does not exist, tip will be displayed.
let cbs = vm._events[event]
Copy the code
Gets all event event handlers. Finally, invokeWithErrorHandling is called to trigger the $ON or $once binding event handler. Finally, return to the VM.
Reprinted from the author: lovers vue link: www.jianshu.com/p/f34e78bfe… The copyright of the book belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.