事件冒泡与事件委托笔记

1,事件冒泡:当一个子元素的事件被触发的时候(如onclick事件),该事件会从事件源(被点击的子元素)开始逐级向上传播,触发父级元素的点击事件

    子元素在没有定义具体的click处理函数的时候,仍然可以冒泡触发父元素的click事件

    只有相应的事件会发生事件冒泡,不想管的事件不受影响(注:由于click为鼠标的点击,所以同样会触发mousedown与mouseup等相关事件,同时发生冒泡)

    阻止事件冒泡:在事件触发时,会传入一个相应的event对象,其中有一个stopPropagation()可以阻止事件冒泡(IE中为cancleBubble=true)

2,事件委托:将子元素的事件通过冒泡的形式交给父元素来执行

    事件委托可以在遍历每一个栏目的时候,减少DOM操作次数

    让事件效果只有点击事件源才会触发,标准浏览器使用ev.target,IE浏览器用event.srcElement

    例:只有点击li会触发事件,且每次只执行一次dom操作

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

    上面这个例子是所有的li执行同样的效果,要是每个li被点击的效果都不一样,也可以优化:

    例:

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

    但是还有一个问题,当新添加节点时,新增的节点是没有事件的

    例: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;
            
            function mHover () {
                //鼠标移入变红,移出变白
                for(var i=0; i<aLi.length;i++){
                    aLi[i].onmouseover = function(){
                        this.style.background = 'red';
                    };
                    aLi[i].onmouseout = function(){
                        this.style.background = '#fff';
                    }
                }
            }
            mHover ();
            //添加新节点
            oBtn.onclick = function(){
                num++;
                var oLi = document.createElement('li');
                oLi.innerHTML = 111*num;
                oUl.appendChild(oLi);
                mHover ();
            };
        }

    再用事件委托,优化如下:

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

    说明,当用事件委托时,不需要遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都在js里面执行,这样可以大大减少dom操作,这是事件委托的精髓。

    再给一个场景 ul > li > div > p,当div占满li,p占满div,还是给ul绑定事件,需要判断点击的是否为li,代码如下:

    

<ul id="test">
        <li>
            <p>11111111111</p>
        </li>
        <li>
            <div>
                22222222
            </div>
        </li>
        <li>
            <span>3333333333</span>
        </li>
        <li>4444444</li>
    </ul>

    解决办法,核心在于while循环,递归调用,也可以写成一个函数,用递归的方法来调用,同时用到冒泡原理,直到currentTarget为止,当当前的target为li时,就可以执行对应事件了

    

var oUl = document.getElementById('test');
    oUl.addEventListener('click',function(ev){
        var target = ev.target;
        while(target !== oUl ){
            if(target.tagName.toLowerCase() == 'li'){
                console.log('li click~');
                break;
            }
            target = target.parentNode;
        }
    })

    总结:

    适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress

    而mouseover和mouseout虽然也有事件冒泡,但在处理它们的时候,需要经常计算它们的位置,处理起来不太容易

    不适合的就很多,比如focus blur等,本身没有冒泡属性

    

猜你喜欢

转载自blog.csdn.net/x1151605848/article/details/81566207
今日推荐