Exploring vue source code-Event System

Source: Internet
Author: User
Tags event listener
Exploring vue source code-Event System

This code is located in vue/src/CORE/instance/events. js

After the lifecycle, You need to initialize the attributes and methods related to the event. The code of the entire event system is very short compared to other modules. Let's take a look at its implementation in several parts.

Header reference
import {  tip,  toArray,  hyphenate,  handleError,  formatComponentName} from '../util/index'import { updateListeners } from '../vdom/helpers/index'

Some of the tool Methods referenced in the header are not difficult. You can view the corresponding file for details. The only thing worth noting is thatupdateListenersMethod. As the name suggests, it is used to update the listener. As for why there is such a method, it is mainly because if the parent component of the instance already has some event listeners, in order to correctly capture the events and bubble up, parent-level events need to be inherited, which is evidenced by the following initialization Code. In addition, if an event processor with the same name is bound during instance initialization, you also need to add a new processor for events with the same name to bind multiple listeners of the same event.

Event Initialization
// Define and export the initevents function. Accept the initevents (Vm: component) {// create the _ Events attribute of the instance and initialize it as an empty object VM. _ Events = object. create (null) // create the _ hashookevent attribute of the instance and initialize it to false VM. _ hashookevent = false // initialize parent event // init parent attached events const listeners = VM. $ options. _ parentlisteners // if a parent-level event exists, update the instance event listener if (listeners) {updatecomponentlisteners (Vm, listeners) }}// set the target value, with the target being to reference the instance let tar Get: Any // Add an event function. It accepts the event name, event processor, and whether to execute the function add (event, FN, once) {If (once) {target. $ once (event, FN)} else {target. $ on (event, FN) }}// remove the event function, and accept the function remove (event, FN) {target. $ off (event, FN)} // defines and exports the updatecomponentlisteners function and accepts the instance object. The new and old listener parameters export function updatecomponentlisteners (Vm: component, listeners: object, oldlisteners :? Object) {// set target to VM target = VM // execute the update listener function, pass in the new and old event listener object, add event and remove event function, instance object updatelisteners (listeners, oldlisteners | |{}, add, remove, Vm) // set null reference target = undefined}

As shown in the code above, the initialization of the event listening system is to first create two attributes: a private event object and a flag indicating whether an event hook exists, then, determine whether to update the event listener of the current instance based on whether the parent-level event processor exists. How to update the listener, paste the code snippet In the Helper function of the virtual node module to take a closer look.

Update event listener
// Define and export updatelisteners. // accept the new and old event listener objects, add and remove functions and instance object parameters. Export function updatelisteners (on: object, oldon: object, add: function, remove: function, Vm: component) {// defines helper variables such as let name, def, cur, old, event // traverse the new listener object for (name in on) {// assign def and cur a new event object def = cur = on [name] // assign old to old event object old = oldon [name] // standardize the event object and assign it to event. // The normalizeevent function is mainly used to break the passed event modifiers with special prefixes into event objects with specific values event = normalizeevent (name) // the following code is dedicated to the weex framework, processing the parameter attributes of cur variables and formatted event objects/* Istanbul ignore if */If (_ weex _ & amp; isplainobject (DEF )) {cur = def. handler event. params = def. params} // if the new event does not exist, the error message is provided in the non-production environment. Otherwise, no operation is performed if (isundef (cur) {process. env. node_env! = 'Production '& amp; warn ('invalid handler for event "$ {event. name} ": Got '+ String (cur), Vm) // when the old event does not exist} else if (isundef (old )) {// If the FNS attribute of the new event object cur does not exist if (isundef (cur. FNS) {// create a function caller and copy it to cur and on [name] cur = on [name] = createfninvoker (cur )} // Add a new event processor add (event. name, cur, event. once, event. capture, event. passive, event. params) // if the old and new events are not completely equal} else if (cur! = Old) {// use the new event handler to overwrite the old event object's FNS attribute old. FNS = cur // re-copy the event object to on [name] = old }}// traverse the old event listener for (name in oldon) {// if the new event object does not exist if (isundef (on [name]) {// standard event object event = normalizeevent (name) // remove event processor remove (event. name, oldon [name], event. capture )}}}

This code is usednormalizeEventAndcreateFnInvokerTwo main functions are used to update the listener.updateListenersThe function is located in the same file.

  • normalizeEvent: Mainly used to return a Custom Event object. This function accepts four required parameters and two optional parameters, they are the event name attribute, whether to execute once attribute, whether to capture the event capture attribute, whether to use passive mode passive attribute, the event processor handler method, and the event processor parameter Params array. Attributes are easy to understand. Pay special attention to them.once,capture,passiveAttribute. These three attributes are used to modify the event and correspond~,!,&Modifier, and paste an example of use in the official document to reference the event & button modifier. The passive mode is used to prevent the event processor from blocking default events, such<a>The link jump event that comes with the tag. If passive is set to true, the event processor cannot stop the jump even if it is set to block the default event.
on: {  '!click': this.doThisInCapturingMode,  '~keyup': this.doThisOnce,  '~!mouseover': this.doThisOnceInCapturingMode}
  • createFnInvoker: Receives an FNS parameter. You can input an event processor function or an array containing multiple processors. This function internally definesinvokerFunction and finally return it. The function has a FNS attribute used to store the input processor. After calling this function, the call of the processor array or the call of a single processor is performed respectively based on the FNS type. This implementation is the process of actually executing the event processor call.
Event-related Prototype Method

In the event initialization process, there are several&Class prototype method at the beginning. They are mounted to the core class in the Mixin function. The methods defined during initialization are encapsulated based on these methods. The specific implementation of binding events, triggering events, and removing events is included in these methods, of course, you will not miss the exploration of these details.

// Export the eventsmixin function and receive the form parameter vue. // use flow for static type check and specify the component class export function eventsmixin (vue: Class & lt; component & gt ;) {// define the hook regular check const hookre =/^ HOOK: // mount the $ on Method to the Vue prototype object // The Event parameter can be a string or an array type, FN is the event listening function // method to return the vue of the instance object itself. prototype. $ on = function (Event: String | array & lt; string & gt;, FN: function): component {// defines the instance variable const VM: component = this // If the input event parameter is an array, traverse the event array and register the FN listener function if (ARRA Y. isarray (event) {for (let I = 0, L = event. length; I <L; I ++) {This. $ on (event [I], FN) }}when the else {// event parameter is a string, check whether the event listening Function Array exists. // if the event listening array exists, add a new listening function. // otherwise, create an empty event listening Function Array and add a new listening function (VM. _ events [event] | (VM. _ events [event] = []). push (FN) // The performance is optimized here. Use the regular expression to check the HOOK: check whether a Boolean value exists // instead of a hash value to find the _ hashookevent value of the Instance Object. // This optimization was made a long time ago. It is not clear what logic the previous hash value search is, for future verification // optimize HOOK: Event cost by usi Ng a Boolean flag marked at registration // instead of a Hash Lookup if (hookre. test (event) {VM. _ hashookevent = true} // return the return Vm of the Instance itself} // Mount $ once method for the vue prototype object // The parameter event only accepts strings, and FN is the listening function vue. prototype. $ once = function (Event: String, FN: function): component {// define the instance variable const VM: Component = this // create the on function on () {// After the function is executed, the on listening function bound to the event is cleared, that is, the function itself // so that the event VM will not be listened on again. $ off (event, On) // run the FN listener function FN on the instance. apply (Vm, arguments)} // set the FN attribute for the on function to ensure that the FN function on is correctly located in the on function. fn = FN // register the on function Vm for the event. $ on (event, on) // return the instance itself return VM} // mount the $ off method to the Vue prototype object // The Event parameter can be a string or array type // FN is a listener function and is an optional parameter vue. prototype. $ off = function (event?: String | array & lt; string & gt;, fn?: Function): component {// defines the instance variable const VM: Component = this // if no parameter is input, clear all events of the Instance Object // set the _ Events private attribute of the Instance Object to null, and return the instance // All if (! Arguments. length) {VM. _ Events = object. create (null) return VM} // if the event parameter is used to input an array, clear the FN listener function of all Event Events and return the instance. // here is the $ off method for Recursive Execution, finally, the listener will be cleared based on a single event // array of events if (array. isarray (event) {for (let I = 0, L = event. length; I <L; I ++) {This. $ off (event [I], FN)} return VM} // if a single event is specified, assign the event listening Function Array to the CBS variable // specific event const CBS = VM. _ events [event] // if this event listening is not registered, the instance if (! CBS) {return VM} // if no listener function is specified, all listener functions for this event are cleared and the instance if (! FN) {VM. _ events [event] = NULL return VM} // If a listener function is specified, the system traverses the array of Event Listeners and removes the IF (FN) instance returned by the specified listener function) {// 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} // attach the $ emit Method to the Vue prototype object and only accept a single event vue. prototype. $ emit = function (Event: string): component {// define the instance variable const VM: Component = this // in a non-production environment, if the input event string is a hump value and has a corresponding lowercase listener event // The system prompts that the event has been registered and the event if (process. Env. node_env! = 'Production ') {const lowercaseevent = event. tolowercase () if (lowercaseevent! = Event & amp; 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 shoshould probably use "$ {hyphenate (event)}" instead of "$ {event }". ')} // Assign an array of event listening functions to CBS let CBS = VM. _ events [event] // If the listener Function Array contains if (CBS) {// reset the CBS variable, why is it hard to use the toarray method to convert the array once? CBS = cbs. Length & gt; 1? Toarray (CBS): CBS // defines all parameters passed in after the event as the ARGs array const ARGs = toarray (arguments, 1) // traverses all listening functions, execute each listening function for the instance and input the ARGs parameter array 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 }}

The content of eventsmixin is very intuitive. It is attached to the prototype object of the instance.$on,$once,$off,$emitFour methods. This is an internal implementation of registering, registering, removing, and triggering instance event listening functions. In the process of use, we will have a clearer understanding of these implementations.

Finally, I have a general understanding of the implementation of the Event System of Vue, and have no special advanced processing, however, the implementation of the Complete Event System has many detailed functions which are not discussed in detail here. For example, the event modifier, you can refer to the official documentation for a clearer understanding. The important role of the Event System is to first develop a set of event handling solutions and standards for the instance, and then to maintain the update of the event listener during the instance data update process, the processing of these two parts requires the most careful consideration.

Original article address: 1190000016757343

Exploring vue source code-Event System

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.