Understand the Event Routing bubble process and delegated proxy mechanism in JavaScript

Source: Internet
Author: User
After I implement this with pure CSS. I started to use JavaScript and style classes to improve functions. Then, I have some ideas. I want to use DelegatedEvents (event Delegate), but I don't want to have any dependencies and insert any...

After I implement this with pure CSS. I started to use JavaScript and style classes to improve functions.

Then, I have some ideas. I want to use Delegated Events (event Delegate), but I don't want to have any dependencies and insert any libraries, including jQuery. I need to delegate the event by myself.

Let's take a look at what event delegation is? How they work and how they implement this mechanism.

Okay. What problems does it solve?

Let's take a look at a simple example.

Let's assume we have a set of buttons. I click a button at a time, and then I want to be set to "active" in the clicked status ". Click again to cancel the active state.

Then, we can write some HTML:

 
 
  • Pencil
  • Pen
  • Eraser

I can use some standard Javascript events to process the above logic:

var buttons = document.querySelectorAll(".toolbar .btn");for(var i = 0; i < buttons.length; i++) {  var button = buttons[i];  button.addEventListener("click", function() {    if(!button.classList.contains("active"))      button.classList.add("active");    else      button.classList.remove("active");  });}

It looks good, but it doesn't actually work as you expected.

Closure traps

If you have some JavaScript development experience, this problem is obvious.

For layman, the button variable is closed, and the corresponding button will be found every time ...... However, there is only one button here; each cycle will be reassigned.

The first loop points to the first button, followed by the second. However, when you click, the button variable always points to the last button element. The problem lies in this.

What we need is a stable scope. Let's refactor it.

var buttons = document.querySelectorAll(".toolbar button");var createToolbarButtonHandler = function(button) {  return function() {    if(!button.classList.contains("active"))      button.classList.add("active");    else      button.classList.remove("active");  };};for(var i = 0; i < buttons.length; i++) {  buttons[i].addEventListener("click", createToolBarButtonHandler(buttons[i]));}

Note * The above code structure is a bit complicated. You can also use a closure to close and save the current button variable, as shown below:

var buttons = document.querySelectorAll(".toolbar .btn");for(var i = 0; i < buttons.length; i++) {  (function(button) {    button.addEventListener("click", function() {      if(!button.classList.contains("active"))        button.classList.add("active");      else        button.classList.remove("active");    });  })(buttons[i])}

Now it works properly. Pointing to a button is always correct

So what are the problems with this solution?

This solution looks good, but we can do better.

First, we have created too many processing functions. Binds an event listener and a callback for each matched. toolbar button. If there are only three buttons, this type of resource allocation can be ignored.

However, what if we have 1000?

 
 
  • Foo
  • Bar
  • // ... 997 more elements ...
  • baz

It will not crash, but it is not the best solution. We allocated a large number of unnecessary functions. Let's refactor and append it only once, that is, bind only one function to handle thousands of possible calls.

Compared with the closed button variable to store the objects we clicked at that time, we can use the event object to get the objects we clicked at that time.

The event object has some metadata. In the case of multiple bindings, we can use currentTarget to obtain the currently bound object. The code in the above example can be changed:

var buttons = document.querySelectorAll(".toolbar button");var toolbarButtonHandler = function(e) {  var button = e.currentTarget;  if(!button.classList.contains("active"))    button.classList.add("active");  else    button.classList.remove("active");};for(var i = 0; i < buttons.length; i++) {  button.addEventListener("click", toolbarButtonHandler);}

Good! However, this only simplifies a single function and makes it more readable. However, it is bound multiple times.

However, we can do better.

Let's assume that we dynamically add some buttons in this list. Then we need to add and remove event Bindings for these dynamic elements. Then we need to persist the variables used by these processing functions and the current context, which sounds unreliable.

There may be other methods.

Let's first fully understand how events work and how they are passed in the DOM.

How events work

When a user clicks an element, an event is generated to notify the user of the current behavior. An event has three phases in dispatching:

  • Capture phase: Capturing

  • Trigger phase: Target

  • Bubble stage: Bubbling

This event starts from before the document and finds the object clicked by the current event all the way down. When the event reaches the clicked object, it returns the result as the original (bubble process) until the entire DOM tree is exited.

Here is an example of HTML:

  
 
 
  • Button A
  • Button B
  • Button C

When you click Button A, the path of the event is as follows:

START| #document  \| HTML        || BODY         } CAPTURE PHASE| UL          || LI#li_1    /| BUTTON     <-- TARGET PHASE| LI#li_1    \| UL          || BODY         } BUBBLING PHASE | HTML        |v #document  /END

Note: this means that you can capture the event generated by clicking on the event path. We are very sure that the event will pass through the ul element of its parent element. We can bind our event processing to the parent element, and then simplify our solution. This is called the event Delegate and proxy (Delegated Events ).

Note * In fact, the event mechanism developed by Flash, Silverlight, and WPF is very similar. Here is their event flowchart. In addition to the event model with only the bubble phase used by Silverlight 3 in earlier IE versions, there are basically three stages. (The old version of IE and Server Load balancer only processes events from triggering object bubbling to the root object, possibly to simplify the event processing mechanism .)

Event delegate agent

Delegate (proxy) events are events bound to parent elements, but they are moved only when certain matching conditions are met.

Let's take a look at a specific example. Let's look at the tool bar example above:

 
 
  • Pencil
  • Pen
  • Eraser

Because we know that clicking the button element will bubble to the UL. toolbar element, let's put event processing here. We need to make a slight adjustment:

var toolbar = document.querySelector(".toolbar");toolbar.addEventListener("click", function(e) {  var button = e.target;  if(!button.classList.contains("active"))    button.classList.add("active");  else    button.classList.remove("active");});

In this way, we have cleared a lot of code and there is no loop. Else we used e.tar get to replace the previous e. currentTarget. This is because event listening is performed on different layers.

  • E.tar get is the object of the currently triggered event, that is, the object to which the user actually clicks.

  • E. currentTarget is the object for processing the event, that is, the object bound to the event.

In our example, E. currentTarget is UL. toolbar.

Note * In fact, there are more than event mechanisms. In the UI architecture, the implementation of FLEX (not Flash), Silverlight/WPF/Android is very similar to that of WEB, and XML (HTML) is used) implement template and element structure organization, Style (CSS) Implement display Style and UI, and control scripts (AS3, C #, Java, JS. However, Web is more open than other platforms, but there are more historical issues. However, almost all platforms support Web standards and are embedded with embedded Web rendering mechanisms like WebView. Compared with the complex front-end UI frameworks and learning curves of various platforms, implementing Native APP front-end UI using Web technology is a very low-cost option.

  

The above is to understand the Event Routing Bubbling Process and the delegated proxy mechanism in JavaScript. For more information, see PHP Chinese Network (www.php1.cn )!

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.