Written in front
Because I am very interested in it, and the technology stack I work in my daily life is the same. I have spent some time studying and learning the source code in the past few months, and have summarized and output it.
Original address of the article:/answershuto/learnVue。
During the learning process, Vue was added with Chinese annotations/answershuto/learnVue/tree/master/vue-src, I hope it can be helpful to other friends who want to learn Vue source code.
There may be some deviations in understanding. Please note that you should learn together and make progress together.
Vue Event API
As we all know, we provide four event APIs, namely $on](/v2/api/#vm-on-event-callback),[$once,$off](/v2/api/#vm-off-event-callback),[$emit。
Initialize event
Initialize the event Create a _events object on the vm to store the event. The content of _events is as follows:
{ eventName: [func1, func2, func3] }
Store event names and corresponding execution methods.
/*Initialization Event*/ export function initEvents (vm: Component) { /* Create a _events object on the vm to store events. */ vm._events = (null) /*This bool flag bit indicates whether there is a hook, and does not need to search for whether there is a hook through the hash table method. This can reduce unnecessary overhead and optimize performance. */ vm._hasHookEvent = false // init parent attached events /* Events that initialize parent component attach*/ const listeners = vm.$options._parentListeners if (listeners) { updateComponentListeners(vm, listeners) } }
$on
The $on method is used to listen for a custom event on the vm instance, which can be triggered by $emit.
.$on = function (event: string | Array<string>, fn: Function): Component { const vm: Component = this /*If it is an array, recursively $on, binding the method to each member*/ if ((event)) { for (let i = 0, l = ; 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 /* When registering an event, the bool value is marked as a flag to indicate that there is a hook, and there is no need to use the hash table method to find out whether there is a hook. This can reduce unnecessary overhead and optimize performance. */ if ((event)) { vm._hasHookEvent = true } } return vm }
$once
$once listens for an event that can only be triggered once, and the event will be automatically removed after it is triggered.
.$once = function (event: string, fn: Function): Component { const vm: Component = this function on () { /*Destroy the event on the first execution*/ vm.$off(event, on) /*How to execute registration*/ (vm, arguments) } = fn vm.$on(event, on) return vm }
$off
$off is used to remove custom events
.$off = function (event?: string | Array<string>, fn?: Function): Component { const vm: Component = this // all /*If no parameters are passed, all events will be cancelled*/ if (!) { vm._events = (null) return vm } // array of events /*Recursively log out event if event is an array*/ if ((event)) { for (let i = 0, l = ; i < l; i++) { this.$off(event[i], fn) } return vm } // specific event const cbs = vm._events[event] /*Github:/answershuto*/ /*If this event does not exist in itself, it will be returned directly*/ if (!cbs) { return vm } /*If only event parameters are passed, all methods under this event method will be cancelled*/ if ( === 1) { vm._events[event] = null return vm } // specific handler /*Travel to find the corresponding method and delete it*/ let cb let i = while (i--) { cb = cbs[i] if (cb === fn || === fn) { (i, 1) break } } return vm }
$emit
$emit is used to trigger the specified custom event.
.$emit = function (event: string): Component { const vm: Component = this if (.NODE_ENV !== 'production') { const lowerCaseEvent = () 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) { /*Convert object of class array into array*/ cbs = > 1 ? toArray(cbs) : cbs const args = toArray(arguments, 1) /*Travel execution*/ for (let i = 0, l = ; i < l; i++) { cbs[i].apply(vm, args) } } return vm }
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.