jquery Event binding uncoupling mechanism source code Analysis _jquery

Source: Internet
Author: User
Tags extend unique id delete cache

Introduction

Why is jquery able to unlock events without passing callback functions? As follows:

$ ("P"). On ("click", Function () {
  alert ("the paragraph is clicked.");

$ ("#box1"). Off ("click");

Event binding Solution Mechanism

When the on function is called, an event data is generated, structured as follows:

{
  Type:type,
  origtype:origtype,
  data:data,
  Handler:handler,
  guid:guid,
  selector: Selector,
  needscontext:needscontext,
  namespace:namespace
}

and adds the data to the element's cache. Each element in jquery can have a cache (generated only when it is needed), which is actually an attribute of that element. jquery creates a queue for each element of each event to hold the event handler function, so you can add multiple event handlers to an element. The structure of the cache is as follows:

' Div#box ': {//Element
  ' Jquery623873 ': {//Element cache
    ' events ': { 
      ' click ': [
       {  //] event data type for element Click event
             : 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
               }
      ]
  }
}

If you do not specify the FN parameter when you want to unpack the event, jquery takes the handler queue of the event to be unbound from the cache of the element, takes the FN parameter from the inside, and then invokes RemoveEventListener for the binding.

Source

Code comments may not be clear enough to be copied out to see

The On,one,off method in the jquery prototype:

Event bindings start from here

JQuery.fn.extend ({

  on:function (types, selector, data, FN) {return in
    (this, types, selector, data, FN);
  },
  one:function (types, selector, data, FN) {return on
    (this, types, selector, data, FN, 1);
  },
  off:f Unction (types, selector, fn) {

    ///This omits the code return This.each for processing parameters (

    function () {
      JQuery.event.remove (this, Types, FN, selector);
    );
  }
} );

The on function that is called independently for one and on:

function on (elem, types, selector, data, FN, one) {
  var origfn, type;

  The code//of the processing parameter is omitted here

  by one binding, yes. Use a function to proxy the current event callback function, the proxy function executes only once
  //the proxy mode
  if (one = = 1) {   
    ORIGFN = fn;< C7/>FN = function (event) {

      //Can use a empty set, since event contains the info
      jQuery (). Off (event);
      Return origfn.apply (this, arguments);

    Use same GUIDs so caller can remove using ORIGFN
    fn.guid = Origfn.guid | | (Origfn.guid = jquery.guid++);
  }

  /************************************************
  * * * jquery will all the selected elements into an array, and then
  * * * For each element to the Add method binding event using the Event object
  *************************************************/return
  Elem.each ( function () {
    JQuery.event.add (this, types, FN, data, selector);
  }


The code that handles the parameter can also look at it, implementing on ("click", Function () {}) to call On:function (types, selector, data, FN) without error. In fact, internal judgment, if data, fn parameter is empty, assign selector to FN

The event object is one of the key objects of the events binding:

This handles the work of binding events to elements and adding 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 = Datapriv.get (elem); This sentence will check if Elem is cached, and if not, a cache will be created to add to the elem element. Forms such as: elem["jQuery310057655476080253721"] = {}//Don ' t attach events to NoData or text/comment nodes (but allow Plai
    n objects) if (!elemdata) {return;
      }//The user can pass in a custom data object instead of the event callback function and place the event callback function in the handler property of the data object if (handler.handler) {Handleobjin = handler;
      handler = Handleobjin.handler;
    selector = Handleobjin.selector;
    //each event callback function will generate a unique ID, which will be used if (!handler.guid) {handler.guid = jquery.guid++ in the future find/remove; ///If the element first binds the event, the event data structure and primary callback function (main) of the element is initialized (main)/description: Each element has a primary callback function as the entry point for the callback that binds multiple events to the element (!) (! events = Elemdata.ev
    Ents)) {events = Elemdata.events = {}; }//This is the code that initializes the main callback function if (!) (Eventhandle = ElemdatA.handle)) {eventhandle = Elemdata.handle = function (e) {//Discard the second event of a Jquery.even T.trigger () and//when the called after a page has unloaded return typeof jQuery!== "undefined"
          && jQuery.event.triggered!== e.type?
      JQuery.event.dispatch.apply (Elem, arguments): undefined;
    }; //Handle event bindings, taking into account the possibility of passing in multiple events by space, types = (Types | | ""). Match (rnotwhite) | |
    [ "" ];
    t = types.length; while (t--) {tmp = Rtypenamespace.exec (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, with the special event handlers for the changed type special = JQuery.event.sp ecial[Type] | |

      {}; IF selector defined, determine special event API type, Otherwise given type type = (selector? special.delegateType:special.bindType) | |

      Type Update special based on newly reset type special = jquery.event.special[Type] | |

      {};
        The data object for the event callback function Handleobj = Jquery.extend ({type:type, Origtype:origtype, Data:data, Handler:handler, Guid:handler.guid, Selector:selector, Needscontext:selector && JQ
      Uery.expr.match.needsContext.test (selector), Namespace:namespaces.join (".")

      }, Handleobjin);  Adding the first binding of the class event initializes an array as an event callback function queue, each of which 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; 
      }//Join to 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//To track which incidents were never used to optimize Jquer
    y.event.global[type] = true;

 }

  }
};

Be aware that objects and arrays are references! For example, to save the event data to the cached code:

handlers = events[Type] = [];

if (selector) {
  handlers.splice (handlers.delegatecount++, 0, handleobj);
} else {
  Handlers.push (handleob j);
}

Handlers change, events[type] will change at the same time.

Datapriv is the object that manages caching:

The job is to create an attribute for the element, which is an object, and then put the information associated with that element into the object and cache it. This requires the use of the object's information, as long as you know the object can get:

function Data () {This.expando = Jquery.expando + data.uid++;}

Data.uid = 1; The deletion section is useless to code data.prototype = {Cache:function (owner) {//Fetch cache, visible cache is a property of target object var value = owner[This.expa

    Ndo];

      If the object is not yet cached, create an if (!value) {value = {};
      We can accept data for non-element nodes at modern browsers,//But we should not, #8335.
      Always return a empty object. if (Acceptdata (owner) {//If It is a node unlikely to being stringify-ed or looped over//use plain a

        Ssignment if (owner.nodetype) {owner[This.expando] = value;
        Otherwise secure it non-enumerable property//Configurable must is true to allow the Deleted when the data is removed} else {Object.defineproperty (owner, This.expando, {VA
        Lue:value, configurable:true});
  }} return value; }, Get: function (owner, key) {return key = = undefined? This.cache (owner)://Always use CamelCase key (gh-2257) hump named 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 the keys if (Jquery.isarray key
        ) {//If key is an array of keys ...//We always set CamelCase keys, so remove.
      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 D OM nodes, so set to undefined instead//https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (Bug restricte
      d) 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 the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.