Home >Web Front-end >JS Tutorial >Detailed explanation of Javascript event delegation

Detailed explanation of Javascript event delegation

巴扎黑
巴扎黑Original
2017-07-24 16:02:481252browse

Cause:

1. This is a classic question type for front-end interviews. It is still helpful to ask your work partners to check it out;

2. In fact, I have never figured it out. I wrote this first as a reminder, and secondly as a reference for other friends who know it but don’t know why;

Overview:

What about that? What about event delegation? It also has a name called event proxy. In terms of advanced JavaScript programming: event delegation uses event bubbling to manage all events of a certain type by specifying only one event handler. So what does this mean? The experts on the Internet basically use the same example when talking about event delegation, which is to take express delivery to explain this phenomenon. I thought about it carefully and found that this example is really appropriate. I will not think of other examples to explain it. Let me pick some flowers to offer to Buddha. Let’s take a closer look at the principle of event delegation:

Three colleagues are expected to receive express delivery on Monday. There are two ways to sign for the express delivery: one is to have three people waiting for the express delivery at the door of the company; the other is to entrust the receptionist to sign for it on your behalf. In reality, we mostly use the entrusted solution (the company will not tolerate so many employees standing at the door just waiting for express delivery). After the MM at the front desk receives the express delivery, she will determine who the recipient is, then sign for it according to the recipient's requirements, and even pay for it on her behalf. Another advantage of this solution is that even if new employees come to the company (no matter how many), the front desk MM will verify and sign for the express delivery after receiving it.

There are actually two levels of meaning here:

First, the colleagues at the front desk can now sign for it, that is, the existing dom node in the program has events;

Second, new employees can also be signed for by the front desk MM, that is, the newly added dom node in the program also has events.

Why use event delegation:

Generally speaking, DOM needs to have an event handler, we will just set the event handler directly for it, then if there are a lot of DOM that need to be added What about event handling? For example, we have 100 li's, and each li has the same click event. Maybe we will use a for loop method to traverse all li's and then add events to them. What will be the impact of this?

In JavaScript, the number of event handlers added to the page will be directly related to the overall running performance of the page, because it needs to constantly interact with the dom node. The more times the dom is accessed, the more likely it is to cause the browser to crash. The more times you draw and reorder, the longer the interactive readiness time of the entire page will be. This is why one of the main ideas of performance optimization is to reduce DOM operations; if you want to use event delegation, all operations will be When placed in a js program, the operation with the dom only needs to be interacted with once, which can greatly reduce the number of interactions with the dom and improve performance;

Each function is an object, and the object will occupy it Memory, the more objects there are, the greater the memory usage, and naturally the performance will be worse (not enough memory is a flaw, haha). For example, the 100 li above will occupy 100 memory space. If it is 1,000 , 10,000, I can only say haha. If we use event delegation, then we can only operate on the object of its parent (if there is only one parent), so we only need a memory space. , if you save a lot, the performance will naturally be better.

Principle of event delegation:

Event delegation is implemented using the bubbling principle of events. What is event bubbling? That is, the event starts from the deepest node, and then gradually propagates the event upward. For example: there is such a node tree on the page, div>ul>li>a; For example, if you add a click event to the innermost a, then this event will be It will be executed layer by layer. The execution sequence is a>li>ul>div. There is such a mechanism. Then we add a click event to the outermost div. Then when the ul, li, and a inside do click events, they will Bubbles to the outermost div, so it will be triggered. This is event delegation, which delegates their parents to execute events on their behalf.

How to implement event delegation:

Finally we have reached the core part of this article, haha, before introducing the method of event delegation, let us first look at an example of a general method:

Child nodes implement the same function:


        
  • 111
  •     
  • 222
  •     
  • 333
  •     
  • 444

To achieve the function, click li, and 123 will pop up:

Detailed explanation of Javascript event delegation
window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<ali.length><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://img.php.cn/upload/article/000/000/001/22e3a06a99eaee066d9e0282007809c3-1.gif" alt="Detailed explanation of Javascript event delegation"></span></div></ali.length>
## The meaning of the above code is very simple. I believe many people implement it this way. Let’s see how many dom operations there are. First, you need to find ul, then traverse li, and then when you click li, you need to find the position of the target li again before you can perform the final operation. You have to find li once every time you click;

Then we use events What happens if we do it by delegation?

window.onload = function(){
    var oUl = document.getElementById("ul1");
   oUl.onclick = function(){
        alert(123);
    }
}

 

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发,不怕,我们有绝招:

Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较(习惯问题):

Detailed explanation of Javascript event delegation

window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
         alert(123);
         alert(target.innerHTML);
    }
  }
}

Detailed explanation of Javascript event delegation

 

这样改下就只有点击li会触发事件了,且每次只执行一次dom操作,如果li数量很多的话,将大大减少dom的操作,优化的性能可想而知!

 

上面的例子是说li操作的是同样的效果,要是每个li被点击的效果都不一样,那么用事件委托还有用吗?

<div>
        <input>
        <input>
        <input>
        <input>
    </div>
Detailed explanation of Javascript event delegation
window.onload = function(){
            var Add = document.getElementById("add");
            var Remove = document.getElementById("remove");
            var Move = document.getElementById("move");
            var Select = document.getElementById("select");
            
            Add.onclick = function(){
                alert('添加');
            };
            Remove.onclick = function(){
                alert('删除');
            };
            Move.onclick = function(){
                alert('移动');
            };
            Select.onclick = function(){
                alert('选择');
            }
            
        }
Detailed explanation of Javascript event delegation

 

上面实现的效果我就不多说了,很简单,4个按钮,点击每一个做不同的操作,那么至少需要4次dom操作,如果用事件委托,能进行优化吗?

Detailed explanation of Javascript event delegation
window.onload = function(){
            var oBox = document.getElementById("box");
            oBox.onclick = function (ev) {
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLocaleLowerCase() == 'input'){
                    switch(target.id){
                        case 'add' :
                            alert('添加');
                            break;
                        case 'remove' :
                            alert('删除');
                            break;
                        case 'move' :
                            alert('移动');
                            break;
                        case 'select' :
                            alert('选择');
                            break;
                    }
                }
            }
            
        }
Detailed explanation of Javascript event delegation

 

用事件委托就可以只用一次dom操作就能完成所有的效果,比上面的性能肯定是要好一些的 

 

 现在讲的都是document加载完成的现有dom节点下的操作,那么如果是新增的节点,新增的节点会有事件吗?也就是说,一个新员工来了,他能收到快递吗?

看一下正常的添加节点的方法:

Detailed explanation of Javascript event delegation
<input>
    
            
  • 111
  •         
  • 222
  •         
  • 333
  •         
  • 444
  •     
Detailed explanation of Javascript event delegation

 

现在是移入li,li变红,移出li,li变白,这么一个效果,然后点击按钮,可以向ul中添加一个li子节点

 

Detailed explanation of Javascript event delegation
window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            
            //鼠标移入变红,移出变白
            for(var i=0; i<ali.length><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://img.php.cn/upload/article/000/000/001/8e05a80ecdb75cfe19baae0423d6c017-11.gif" alt="Detailed explanation of Javascript event delegation"></span></div></ali.length>

 

这是一般的做法,但是你会发现,新增的li是没有事件的,说明添加子节点的时候,事件没有一起添加进去,这不是我们想要的结果,那怎么做呢?一般的解决方案会是这样,将for循环用一个函数包起来,命名为mHover,如下:

Detailed explanation of Javascript event delegation
window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            
            function mHover () {
                //鼠标移入变红,移出变白
                for(var i=0; i<ali.length><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://img.php.cn/upload/article/000/000/001/8e05a80ecdb75cfe19baae0423d6c017-13.gif" alt="Detailed explanation of Javascript event delegation"></span></div></ali.length>

 

虽然功能实现了,看着还挺好,但实际上无疑是又增加了一个dom操作,在优化性能方面是不可取的,那么有事件委托的方式,能做到优化吗?

Detailed explanation of Javascript event delegation
window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            
            //事件委托,添加的子元素也有事件
            oUl.onmouseover = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "red";
                }
                
            };
            oUl.onmouseout = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "#fff";
                }
                
            };
            
            //添加新节点
            oBtn.onclick = function(){
                num++;
                var oLi = document.createElement('li');
                oLi.innerHTML = 111*num;
                oUl.appendChild(oLi);
            };
        }
Detailed explanation of Javascript event delegation

 

看,上面是用事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作,这才是事件委托的精髓所在。

 

--------------------------------------------------华丽的分割线-------------- -----------------------------------------------------------------------------------------------------

在这里先感谢一下@苍茫大地NV 的提问,提的问题非常好!

The above is the detailed content of Detailed explanation of Javascript event delegation. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn