"jquery Source" event delegate

Source: Internet
Author: User
Tags add time

There are several outstanding features of JQuery's event binding:

1. Can bind an unlimited number of processing functions

2. Events can be delegated to an ancestor node, not necessarily tied to the corresponding node, so that the added node can be processed as well.

3. Chain-Operated

  

The following is the principal analysis of the event's delegate design. The event source we become the delegate node, the delegate node entrusts his ancestor node to perform the event processing for him, this ancestor node becomes the delegated node.

The native event of the DOM binds the processing to the corresponding node, and the corresponding node triggers the event to perform the processing. Delegate event handling to the ancestor node, which is attached to the ancestor node. What needs to be done is that the original node triggers the event and wants to perform the event processing that has been attached to the ancestor node so that the ancestor node needs to trigger the same event, and that the original node is actually triggered. How can this be done? The event bubbling mechanism provides this possibility.

A. In-depth understanding of event bubbling

Let's start with a self-drawn event model.

The DOM's event flow is divided into three stages:

First stage: Event capture. The so-called event capture is the process of finding the most accurate source of events (the node that triggers the event, the #small node in the model), starting at the maximum range (document) and looking down at the first level. To give a simple example, to find a school B grade C Class D classmate, then I have to find a school, and then find B grade, and then found in Class C, finally I can accurately find D classmates.

Second stage: Event triggering. The event source is found and the corresponding event (if any) of the binding should be executed next. For example: Tell D to 12 (this is like the type of event), then D will know that it is time to eat lunch, and then go to lunch (do the corresponding event).

Phase three: Event bubbling. After the event source finishes processing the event. This type of event is passed to the ancestor node until the document (including document) (which, of course, is based on the premise that the event bubbling is not blocked). This means that each ancestor node of the event source triggers a similar event. Or the above example, D classmate went to dinner, then Class C know to 12 (event type), and then the class after school (execution) ... Finally a school also received a 12-point message (type of event), and then the school bell rang (to perform the event). Of course, this is just an example, the contents of which do not need to be taken seriously.

  

Event bubbling is such a good feature that jquery certainly has to make good use of. An event source triggers an event, and its ancestor node must also trigger the event, and the ancestor knows that the event source that bubbled up to me is the descendant node (event.target). This provides the necessary conditions for the event delegate.

Imagine that the event source a triggers the Click event's processing delegate to its ancestor Node B. When the A node triggers the click and the event bubbles to B, the B node also triggers the Click event, and B sees a delegate event in the event list, which holds the selector for the delegate node, which is the event source A. Then b executes the delegate event immediately (of course, jquery is more complicated, as long as the node is a to B and the event type is the same as the event that triggered it).

Give an example

<style>    #big {      width:400px;      height:400px;      Background-color: #00f;    }    #middle {      width:200px;      height:200px;      Background-color: #000;    }    #small {      width:100px;      height:100px;      Background-color: #f00;    } </style><div id= "Big" ><div id= "Middle" ><div id= "small" ></div></div></div >
<script>  document.getElementById (' big '). onclick = function () {Console.log ("Big clicked!")}  document.getElementById (' Middle '). onclick = function () {Console.log ("Middle clicked!")}  document.getElementById (' small '). onclick = function () {Console.log ("Small clicked!")} </script>

Click on the smallest red block (#small). Execution results are as follows

  

B. jquery event delegate processing process

In the previous chapter analysis of the JQuery.event.add time has analyzed the event binding, and then the binding part of the source code to extract

if (! ( Eventhandle = Elemdata.handle)) {Eventhandle= Elemdata.handle = function (e) {//When an event is called and the page has been unloaded, discard the second event of JQuery.event.trigger (), return typeof            JQuery!== core_strundefined && (!e | | jQuery.event.triggered!== e.type)?        JQuery.event.dispatch.apply (Eventhandle.elem, arguments): undefined;        };    Elem is used as a feature of the handle function to prevent memory leaks caused by IE non-local events Eventhandle.elem = Elem; }
...
Non-custom events, if the special event handler returns FALSE, you can only use Addeventlistener/attachevent if (!special.setup | | special.setup.call (ele m, data, namespaces, eventhandle) = = = False) {//Bind the element global event if (Elem.addeventlistener) { Elem.addeventlistener (Type,Eventhandle, false); } else if (elem.attachevent) {elem.attachevent ("on" + type,Eventhandle); } }

The event handler that is bound to Elem is Eventhandle, and the actual execution of Eventhandle is the event dispatch JQuery.event.dispatch. The process of event scheduling is actually the process of handling delegate events, because the response processing of this node will eventually be appended to the delegate processing list.

The event dispatch process is

1. Constructs a writable Jquery.event object from the local event object event. Use this object to replace the local event object in the argument

Constructs a writable jquery.eventevent = JQuery.event.fix (event) from the local event object;
...
Using a fixed jquery.event instead of (read-only) Local events
Args[0] = event;
Event.delegatetarget = this;

The structure of the local events event is as follows

  

A new event object constructed using local events jquery.event structure as follows

  

Where the value of the Originalevent property is the local event object. The constructed event object has many properties that are extracted directly from the local event object.

2. Get the event-handling list for the corresponding event type in the current node cache

        Handlers = (Jquery._data (This, "events") | | {}) [Event.type] | | [],

The order of the event processing list is that the delegate event is processed in front, and finally the event handler is bound directly to the current node.

3. Replace the caller of the jQuery.event.handlers with the current node and execute it to obtain a qualified delegate handler queue (this queue will end up with processing events bound to the node itself)

Gets the specified event processing queue, primarily using the Event.target event source node to constantly loop up to find the parent node,//To see if the node is in the node corresponding to the selector in handlers Handlerqueue = JQuery.event.handlers.call (This, event, handlers);

Detailed analysis of the jQuery.event.handlers in the request to obtain the qualified delegate handler function queue.

JQuery.event.handlers first takes the delegate event handler out and puts it in the processing queue handlerqueue.

The process of finding is: First take out the event source cur = event.target, and then in the case of determining that there is a delegate processing the source begins to query his ancestor node, Iterates over each delegate event in the delegate event list specifies whether the specified response node (as specified by the selector of the Delegate event processing object) contains the query's node "Handleobj.needscontext? JQuery (SEL, this)." Index (cur) >= 0:jquery.find (SEL, this, NULL, [cur]). Length ", if included, presses the delegate processing into the event-handling queue handlerqueue. The source code is as follows

if (Delegatecount && cur.nodetype && (!event.button | | event.type!== "click")) {//Bubble parent node, find matching delegate event to deposit ha Ndlerqueue queue for (; cur! = this, cur = Cur.parentnode | | this) {if (Cur.nodetype = = = 1 && (cur.disabled! = = True | |      Event.type!== "click") {matches = []; for (i = 0; i < Delegatecount; i++) {
Avoid and Object.prototype attribute conflicts (#13203)
sel = Handleobj.selector + "";
if (matches[sel] = = = undefined) {
matches[sel] = handleobj.needscontext?
JQuery (SEL, this). Index (cur) >= 0:
Jquery.find (SEL, this, NULL, [cur]). length;
}
          
if (matches[sel]) {
Matches.push (Handleobj);
}
}
Add delegate processing to the queue
if (matches.length) {
Handlerqueue.push ({elem:cur, handlers:matches});
}
}
}
}

Finally, the processing that binds directly to the current node is also pressed into execution

Add directly bound events to the Handlerqueue queue if (Delegatecount < handlers.length) {Handlerqueue.push ({elem:this, handlers:handlers . Slice (Delegatecount)});}

  

4. Execute the handler function in the event handling queue Handlerqueue

//Run the agent first, they may be blocking bubbles, we can take advantage of this i = 0;while ((matched = handlerqueue[i++]) &&!event.ispropagationstopped ())        {event.currenttarget = Matched.elem;        j = 0; while ((handleobj = matched.handlers[j + +)) &&!event.isimmediatepropagationstopped ()) {//Trigger event Condition: 1  No namespace, or//2) has a subset of namespaces or equals those boundary events (both of them can have no namespace) if (!event.namespace_re | | event.namespace_re.test (                Handleobj.namespace)) {event.handleobj = Handleobj;                Event.data = Handleobj.data; Perform ret = ((jquery.event.special[Handleobj.origtype] | | {}). Handle | |                Handleobj.handler). Apply (Matched.elem, args); if (ret!== undefined) {if ((Event.result = ret) = = = False) {Event.prevent                        Default ();                    Event.stoppropagation (); }                }            }        }    }

 There's a point in there that needs attention . The new event object that is constructed is the event object (Event.currenttarget can testify) of the node being delegated, but the event object is converted to the event object of the delegate node when the delegate is executed (Event.currenttarget = Matched.elem;), which guarantees the correctness of the event object that is called in the event handler being delegated. Example: or the previous piece of HTML, except that the execution code becomes

function Dohander (e) {alert ("Dohander");};  function dot (e) {e.stoppropagation (); Alert ("dot");};
$ (document). On ("Click", ' #big ', Dohander). On ("Click", ' #middle ', dot). On ("Click", ' #small ', dohander);

The "#middle" Node delegates the document node to perform processing Dot,dot a section of code e.stoppropagation (); When you click on the "#middle" node, the event bubbles to document. If the event is not converted to the event of the delegated node before the dot is executed, this block bubbling does not prevent the event bubbling of the "#middle" node, but instead blocks the event bubbling of the document node.

Of course, the event is actually bubbling to the entrusted node document when handling the event being delegated. We are unable to block the already bubbling nodes, such as the "#big" node that has triggered the Click event. However, we can do a simulation to prevent bubbling processing of the Delegate event processing list that is delegated to the document node. Click on the "#middle" node, event bubbling to document, execute JQuery.event.handlers Get delegate event processing list is like this

The delegate event processing of the "#small" node has been filtered out by jQuery.event.handlers handlerqueue = ["#middle" node delegate event processing dot, "#big" node delegate event handling Dohander];

Execute dot in the E.stoppropagation (), Stoppropagation is also overloaded, the source code is as follows

        Stoppropagation:function () {            var e = this.originalevent;            this.ispropagationstopped = returntrue;            if (!e) {                return;            }            If stoppropagation exists, run it on the original event            if (e.stoppropagation) {                e.stoppropagation ();            }            //Support:ie            //Set The Cancelbubble property of the original event to true            e.cancelbubble = true;        }

where this.ispropagationstopped = returntrue; events are marked to block bubbling. After the dot is executed, go to the next delegate handling Handerqueue "#big" node delegate event handling Dohander", here's a judgment

Event event.ispropagationstopped () = Returntrue () = (function returntrue () {return true;}) (); Prevents entry while performing the next delegate processing. OK, the subsequent delegate events are all blocked, so finally clicking on the "#middle" node only executes the DOT function.

  

Simulation prevents the bubbling process from ending.

The following is a more complete example to illustrate, JS code

  function Dohander (e) {    alert ("Dohander");  };  function dot (e) {    e.stoppropagation ();    Alert ("dot");  };  function Dobigonly (e) {    alert ("big");  }  $ (document). On ("Click", ' #big ', Dohander). On ("Click", '  #middle ', dot). On ("click",  ' #small ', dohander);  $ (' #big '). Click (dobigonly);

Click on the "#middle" node to perform the result: alert ("Big") pops up, then alert ("Dot")

  

Process Analysis:

Click "#middle" and there is no binding event on "#middle".

The event bubbles to "#big", and "#big" binds the display alert ("big") that handles the dobigonly straight line.

Events bubble to Body,

Then bubble to HTML,

Finally bubbles to document. There is a binding event on document that filters out the "#small" delegate processing based on the event source. The remaining two delegates ("#middle" delegate processing and "#big" delegate processing) need to be processed. The "#middle" delegate processes the dot, which displays alert ("Dot") to prevent event bubbling. Subsequent delegates are blocked.

"jquery Source" event delegate

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.