Jquery event binding and unbinding mechanism source code parsing, jquery source code

Source: Internet
Author: User
Tags delete cache

Jquery event binding and unbinding mechanism source code parsing, jquery source code

Introduction

Why can Jquery unbind events without returning call functions? As follows:

$("p").on("click",function(){  alert("The paragraph was clicked.");});$("#box1").off("click");

Event binding and unbinding Mechanism

When the on function is called, an event data is generated with the following structure:

{  type: type,  origType: origType,  data: data,  handler: handler,  guid: guid,  selector: selector,  needsContext: needsContext,  namespace: namespace}

And add the data to the element cache. Each element in jquery can have a cache (generated only when necessary), which is actually an attribute of this element. Jquery creates a queue for each event of each element to save the event processing function. Therefore, you can add multiple event processing functions to an element. The cache structure is as follows:

"Div # box": {// element "Jquery623873": {// element cache "events": {"click ": [{// event data type: type, origType: origType, data: data, handler: handler, guid: guid, selector: selector, needsContext: needsContext, namespace: namespace}], "mousemove": [{type: type, origType: origType, data: data, handler: handler, guid: guid, selector: selector, needsContext: needsContext, namespace: namespace}] }}}

When you want to unbind an event, if the fn parameter is not specified, jquery will get the processing function queue of the event to be unbound from the cache of this element, and take out the fn parameter from it, call removeEventListener to unbind the listener.

Source code

The code comments may not be clear. You can copy them to see them.

In the jquery prototype, the on, one, and off methods are as follows:

Event binding starts from here

JQuery. fn. extend ({on: function (types, selector, data, fn) {return on (this, types, selector, data, fn) ;}, one: function (types, selector, data, fn) {return on (this, types, selector, data, fn, 1) ;}, off: function (types, selector, fn) {// The Code return this for processing parameters is omitted here. each (function () {jQuery. event. remove (this, types, fn, selector );});}});

Independent on functions for one and on calls:

Function on (elem, types, selector, data, fn, one) {var origFn, type; // The code for processing parameters is omitted here // whether the code is bound through one, yes, use a function to proxy the current event callback function. The proxy function is only executed once. // The proxy mode is used here if (one = 1) {origFn = fn; fn = function (event) {// Can use an empty set, since event contains the info jQuery (). off (event); return origFn. apply (this, arguments) ;}; // Use same guid so caller can remove using origFn. guid = origFn. guid | (origFn. guid = jQuery. guid ++ );} /*************************************** * *********** jquery puts all selected elements into an array, then ************************ * ***********************/return elem. each (function () {jQuery. event. add (this, types, fn, data, selector );});}

You can also take a look at the code for processing parameters. on ("click", function () {}) is called like this and on: function (types, selector, data, fn) will not cause errors. It is actually an internal judgment. If the data and fn parameters are null, the selector is assigned to the fn

The event object is a key object bound to the event:

Here we will bind the event to the element and add the event information to the element cache:

JQuery. event = {add: function (elem, types, handler, data, selector) {var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = datatev. get (elem); // This statement checks whether elem is cached. If not, a cache is created and added to the elem element. Form: elem ["jQuery310057655476080253721"] ={}// Don't attach events to noData or text/comment nodes (but allow plain objects) if (! ElemData) {return;} // You can input a custom data object to replace the Event Callback Function. Put the Event Callback Function in the handler attribute of the data object if (handler. handler) {handleObjIn = handler; handler = handleObjIn. handler; selector = handleObjIn. selector;} // each event callback function generates a unique id. if (! Handler. guid) {handler. guid = jQuery. guid ++;} // If the element is bound to an event for the first time, the event data structure of the initialization element and the main callback function (main) // Description: Each element has a main callback function, as the callback entry for binding multiple events to this element if (! (Events = elemData. events) {events = elemData. events ={};}// the code for initializing the main callback function if (! (EventHandle = elemData. handle) {eventHandle = elemData. handle = function (e) {// Discard the second event of a jQuery. event. trigger () and // when an event is called after a page has unloaded return typeof jQuery! = "Undefined" & jQuery. event. triggered! = E. type? JQuery. event. dispatch. apply (elem, arguments): undefined;} // handle event binding. Considering that multiple events may be imported by space separation, multi-event processing types = (types | ""). match (rnotwhite) | [""]; t = types. length; while (t --) {tmp = rtypenamespace.exe c (types [t]) | []; type = origType = tmp [1]; namespaces = (tmp [2] | ""). split (". "). sort (); // There * must * be a type, no attaching namespace-only handlers if (! Type) {continue;} // If event changes its type, use the special event handlers for the changed type special = jQuery. event. special [type] | {}; // If selector defined, determine special event api type, otherwise given type = (selector? Special. delegateType: special. bindType) | type; // Update special based on newly reset type special = jQuery. event. special [type] | |{}; // data object of the Event Callback Function handleObj = jQuery. extend ({type: type, origType: origType, data: data, handler: handler, guid: handler. guid, selector: selector, needsContext: selector & jQuery. expr. match. needsContext. test (selector), namespace: namespaces. join (". ")}, h AndleObjIn); // when you bind the event class for the first time, an array is initialized as the Event Callback Function queue. Each event of each element has a queue if (! (Handlers = events [type]) {handlers = events [type] = []; handlers. delegateCount = 0; // Only use addEventListener if the special events handler returns false if (! Special. setup | special. setup. call (elem, data, namespaces, eventHandle) === false) {if (elem. addEventListener) {elem. addEventListener (type, eventHandle) ;}} if (special. add) {special. add. call (elem, handleObj); if (! HandleObj. handler. guid) {handleObj. handler. guid = handler. guid ;}// add to the Event Callback Function queue if (selector) {handlers. splice (handlers. delegateCount ++, 0, handleObj);} else {handlers. push (handleObj);} // Keep track of which events have ever been used, for event optimization // used to track events that have never been used and optimize jQuery. event. global [type] = true ;}}};

Note that objects and arrays are referenced! For example, the code that saves event data to the cache:

handlers = events[ type ] = [];if ( selector ) {  handlers.splice( handlers.delegateCount++, 0, handleObj );} else {  handlers.push( handleObj );}

If handlers is changed, events [type] will change at the same time.

Datatev is the object for managing cache:

The job is to create an attribute for the element. This attribute is an object, and then the information related to this element is put in this object and cached. To use the information of this object, you only need to know the object and get it:

Function Data () {this. expando = jQuery. expando + Data. uid ++;} Data. uid = 1; // The code Data is not used to delete the part. prototype = {cache: function (owner) {// retrieves the cache. It can be seen that the cache is an attribute of the target object. var value = owner [this. expando]; // if the object has not been cached, create an if (! Value) {value = {}; // We can accept data for non-element nodes in modern browsers, // but we shoshould not, see #8335. // Always return an empty object. if (acceptData (owner) {// If it is a node unlikely to be stringify-ed or looped over // use plain assignment if (owner. nodeType) {owner [this. expando] = value; // Otherwise secure it in a non-enumerable property // retriable must be tr Ue to allow the property to be // deleted when data is removed} else {Object. defineProperty (owner, this. expando, {value: value, retriable: true}) ;}} return value ;}, get: function (owner, key) {return key === undefined? This. cache (owner): // Always use camelCase key (gh-2257) hump name owner [this. expando] & owner [this. expando] [jQuery. camelCase (key)] ;}, remove: function (owner, key) {var I, cache = owner [this. expando]; if (cache = undefined) {return;} if (key! = Undefined) {// Support array or space separated string of keys if (jQuery. isArray (key) {// If key is an array of keys... // We always set camelCase keys, so remove that. key = key. map (jQuery. camelCase);} else {key = jQuery. camelCase (key); // If a key with the spaces exists, use it. // Otherwise, create an array by matching non-whitespace key = key in cache? [Key]: (key. match (rnotwhite) | []);} I = key. length; while (I --) {delete cache [key [I] ;}} // Remove the expando if there's no more data if (key = undefined | jQuery. isEmptyObject (cache) {// Support: Chrome <= 35-45 // Webkit & Blink performance suffers when deleting properties // from DOM nodes, so set to undefined instead // https://bugs.chromium.org/p/chromium/issues/ Detail? Id = 378607 (bug restricted) if (owner. nodeType) {owner [this. expando] = undefined;} else {delete owner [this. expando] ;}}, hasData: function (owner) {var cache = owner [this. expando]; return cache! = Undefined &&! JQuery. isEmptyObject (cache );}};

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

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.