JS中的事件委托是什么?

参考:JavaScript事件代理和事件委托

1、定义

事件委托就是利用事件冒泡机制,只指定一个事件处理程序,就可以管理某一类的所有事件

2、为什么要用事件委托?

给DOM添加事件处理程序后,需要不断的与DOM节点进行交互,访问DOM的次数越多,引起浏览器重排和重绘的次数也越多。如果用事件委托,就可以将所有的操作放入到js程序里面,与DOM的操作就只需要交互一次,这样可以大大的减少与DOM的交互次数,提高性能

3、DOM2级事件

  1. 事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的
  2. 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行
  3. 事件冒泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来阻止事件的冒泡传播

4、如何实现事件委托?

(1)当li操作是同样的效果
<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>

无事件委托:

window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }
}

有事件委托:

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

用父级ul做事件代理,当li被点击时,由于冒泡原理,事件就会被冒泡到ul上,因为ul上有点击事件,所以事件就会被触发。注意,此时点击ul,也是会触发的。如何实现只有点击li才会触发?
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们称为事件源。

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);
    }
  }
}
(2)当li操作效果不同
<div id="box">
        <input type="button" id="add" value="添加" />
        <input type="button" id="remove" value="删除" />
        <input type="button" id="move" value="移动" />
        <input type="button" id="select" value="选择" />
 </div>
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.toLowerCase() == 'input'){
                    switch(target.id){
                        case 'add' :
                            alert('添加');
                            break;
                        case 'remove' :
                            alert('删除');
                            break;
                        case 'move' :
                            alert('移动');
                            break;
                        case 'select' :
                            alert('选择');
                            break;
                    }
                }
            }    
        }
(3)如果是新增的节点,会有事件吗?

给每个li节点绑定事件,当没有使用事件委托机制时,新增的li是没有事件的。
无事件委托:

<input type="button" name="" id="btn" value="添加" />
<ul id="ul1">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
</ul>
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;i++){
                aLi[i].onmouseover = function(){
                    this.style.background = 'red';
                };
                aLi[i].onmouseout = function(){
                    this.style.background = '#fff';
                }
            }
            //添加新节点
            oBtn.onclick = function(){
                num++;
                var oLi = document.createElement('li');
                oLi.innerHTML = 111*num;
                oUl.appendChild(oLi);
            };
        }

有事件委托:

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);
            };
        }

当用事件委托的时候,根本不需要去遍历元素的子节点,新增的子元素也带有事件效果。

在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标

document.body.onclick = function(event) {
      alert(event.currentTarget === document.body);  // true
      alert(event.this === document.body);  // true
      alert(event.target === document.getElementById("myBtn"))  //true
    }

this和currentTarget都等于document.body,因为事件是注册到这个元素上的,但是target元素等于按钮元素,因为它是click事件真正的目标。

猜你喜欢

转载自blog.csdn.net/weixin_43912756/article/details/108323533