JavaScript Event Delegation

Source: Internet
Author: User

Basic concepts

Event delegation, in layman's terms, is to put an element in response to an event (click, Focus ...). ) is delegated to another element;

In general, an event of one or a group of elements is delegated to its parent or to the outer element, and the actual bound event is the outer element, and when the event responds to the element that needs to be bound, it is triggered by the event bubbling mechanism to trigger the binding event of its outer element, and then executes the function on the outer element.

For example, for example, a dorm students at the same time express to, one way is they are all silly to pick up, there is one way is to entrust this matter to the dormitory, let a person go out to take all the courier, and then according to the recipient one by one points to each dorm classmate;

Here, take the Courier is an event, each classmate refers to the need to respond to the DOM elements of the event, and go out of the unified collection of express dormitory is the agent element, so the real binding event is this element, according to the recipient distribution process is in the event execution, The event that needs to be judged for the current response should match which or which of the proxied elements.

Event bubbling

As mentioned earlier, the implementation of event delegation in DOM is the mechanism of using event bubbling, what is event bubbling?

In Document.addeventlistener we can set up the event model: event bubbling, event capture, which is generally a model with event bubbling;

As shown, the event model is divided into three stages:

    • Capture phase: In the event bubbling model, the capture phase does not respond to any events;
    • Target stage: The target stage is the event response to the lowest element of the triggering event;
    • Bubbling stage: The bubbling phase is that the triggering response of an event is from the lowest level to the outermost layer (root node), and the event agent is to use event bubbling mechanism to bind the events in the layer to the outer layers; # # # Events
Benefits of Delegation

1. Reduce memory consumption

Imagine that if we had a list with a large list of items, we needed to respond to an event when we clicked on the list item;

<< Span class= "Hljs-name" >ul id= "list" >  <li>item 1</li> <li>item 2</li> Span class= "Hljs-tag" ><li>item 3</ li> ... <li>item n</ li></ul>//... There's an unknown Li in the middle.               

If you bind a function to each list item one by one, it is very large for memory consumption, and it consumes a lot of performance in efficiency;

Therefore, the better way is to bind this click event to his parent layer, which is ' UL ', and then to match the target element when executing the event;

So event delegation can reduce a lot of memory consumption and save efficiency.

2. Dynamically bound events

For example, the list of items in the above examples, we give each list item is bound to the event;

In many cases, we need to add or remove elements of the list item dynamically through AJAX or user operations, so we need to re-bind events to the new element at each change, and unbind events from the elements that are about to be deleted.

If the event delegate is not this kind of trouble, because the event is bound to the parent layer, and the target element is not related to the increase or decrease, the execution to the target element is actually in response to the execution of the event function to match the process;

So using events in the case of dynamically binding events can reduce a lot of repetitive work.

Event Delegation in JQuery

The event delegation in JQuery is believed to have been used by many people, and it is mainly implemented in several ways:

    • $.on: Basic usage: $ ('. Parent '). On (' Click ', ' a ', function () {Console.log (' click event on Tag a ');}), which is the event proxy for the A element below the. Parent element to $ ('. Parent '), as long as there is a click event on this element, it will automatically find the. Parent element under the a element, and then respond to the event;
    • $.delegate: Basic usage: $ ('. Parent '). Delegate (' A ', ' click ', Function () {Console.log (' click event on Tag a ');}), ibid., and a corresponding $. Delegate to remove an agent event;
    • $.live: Basic usage: $ (' A ', $ ('. Parent ')). Live (' click ', Function () {Console.log (' click event on Tag a ');}), as above, however if no parent layer element is passed (. Parent), the event is delegated to $ (document) by default;
Implement the basic implementation of functions

For example, we have an HTML fragment like this:

<< Span class= "Hljs-name" >ul id= "list" >  <li>item 1</li> <li>item 2</li> Span class= "Hljs-tag" ><li>item 3</ li> ... <li>item n</ li></ul>//... There's an unknown Li in the middle.               

Let's implement the delegate of the Li element under #list to its parent layer element, which is #list:

//bind events to parent layer elements document.getelementbyid ( ' list '). AddEventListener ( ' click ', function ( e) {//Compatibility handling var event = e | | window.event; var target = Event.target | | event.srcelement; //determine whether to match the target element if (target.nodeName.toLocaleLowerCase = = =  ' LI ') {console.log ( ' the content is: ', target.innerhtml); }}); 

In the above code, the target element is the element that is clicked under the #list element, and then it can be more accurately matched to a class of #list Li elements by judging some of the properties of the target (e.g., nodename,id, etc.);

Exact match with Element.matches

If you change the HTML into:

<ul id= "list" > <li classname=  "class-1" >item 1</li> <li>item 2</li > <li classname=  "class-1" >item 3</li> ... Span class= "Hljs-tag" ><li>item n</ li></ul>//... There's an unknown Li in the middle.               

Here, we want to delegate the LI element under #list element (and its class class-1) to the #list;

If through the above method we also need to ' if (target.nodeName.toLocaleLowerCase = = = ' LI ') ' judgment in adding a judgment ' target.nodeName.className = = ' class-1′ ';

But if you imagine CSS choosing to do a more flexible match, the above judgment is too much, and it is difficult to do flexibility, here can use the element.matches API to match;

The basic use of the Element.matches API: Element.matches (selectorstring), selectorstring is a CSS-like selector rule, for example, you can use Target.matches ( ' li.class-1′), he returns a Boolean value that returns true if the target element is a label Li and its class is class-1, otherwise it returns false;

Of course, its compatibility has some problems, need IE9 and above the modern browser version;

We can use Polyfill to solve compatibility problems:

if (!    Element.prototype.matches) {Element.prototype.matches = Element.prototype.matchesSelector | |    Element.prototype.mozMatchesSelector | |    Element.prototype.msMatchesSelector | |    Element.prototype.oMatchesSelector | |    Element.prototype.webkitMatchesSelector | | function (s) {var matches = (this.document | | this.ownerdocument). Queryselectorall (s), i = matches.length; while (I. >= 0 && matches.item (i)!== this" {} return i > -1;};    

Together with Element.matches, we will be able to fulfill our needs:

if (!    Element.prototype.matches) {Element.prototype.matches = Element.prototype.matchesSelector | |    Element.prototype.mozMatchesSelector | |    Element.prototype.msMatchesSelector | |    Element.prototype.oMatchesSelector | | Element.prototype.webkitMatchesSelector | |functions) {var matches = (this.document | |this.ownerdocument). Queryselectorall (s), i = matches.length;while (---->= 0 && matches.item (i)!== this ) {} return i > -1;};} document.getElementById (' list '). AddEventListener (' click ', function (e) { //compatibility handling var event = e | | window.event; var target = Event.target | | event.srcelement; if (target.matches (' li.class-1 ')) { Console.log ('The content is: ', target.innerhtml);}}); 
function encapsulation

In dealing with more scenarios, we can encapsulate the function of the event agent into a common function so that it can be reused.

Combine the above example to implement a function eventdelegate, which accepts four parameters:

    • [string] A selector string is used to filter the parent layer elements that need to implement the proxy, both events need to be really bound above;
    • [string] A selector string used to filter the descendants of the selector element that triggered the event, both of which we need to be the element of the agent event;
    • [String] One or more event types separated by spaces and optional namespaces, such as Click or Keydown.click;
    • [function] functions that require proxy event response;

Here are a few key points:

    • There may be more than one element for the parent agent, requiring one by one binding events;
    • There may be more than one event type for the binding, requiring one by one binding events;
    • Compatibility issues need to be taken into account in dealing with the elements that match the agent;
    • You need to pass in the correct parameters when executing the bound function and take into account this problem;
functionEventdelegate (Parentselector, Targetselector, events, foo) {Functions that trigger executionfunctionTrifunction (E) {Compatibility processingvar event = e | |window.event;var target = Event.target | | Event.srcelement;Handling the compatibility of matchesif (! Element.prototype.matches) {Element.prototype.matches = Element.prototype.matchesSelector | | Element.prototype.mozMatchesSelector | | Element.prototype.msMatchesSelector | | Element.prototype.oMatchesSelector | | Element.prototype.webkitMatchesSelector | |functions) {var matches = (this.document | |this.ownerdocument). Queryselectorall (s), i = matches.length;while (-I. >=0 && Matches.item (i)!==This) {}return i >-1; }; }To determine if it matches the elements we need.if (Target.matches (Targetselector)) {Execute the binding function, note this foo.call (target,Array.prototype.slice.call (arguments)); }} //If there are multiple events, all one by one binding event Events.split ('. ') is required. Aone by one binding Array.prototype.slice.call is also required for ForEach (function (evt) { //multiple parent elements) (  Document.queryselectorall (Parentselector)). ForEach (function ($p) {$p. AddEventListener (EVT, Trifunction); }); });}

Learn the front-end classmates
Welcome to join the front-end learning Exchange QQ Group: 461593224

JavaScript Event Delegation

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.