js的事件委托

来源:互联网 发布:银行笔试通过率 知乎 编辑:程序博客网 时间:2024/05/24 05:03

在JavaScript中,添加到页面上的事件处理程序数量直接关系到页面的整体运行性能,导致这一问题的原因:1、每个函数都是对象,都会占用内存,内存中的对象越多,性能就越差;2、必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。

“事件委托”就是用于解决事件处理程序过多的问题,利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

比如:

<ul id ="myLinks">      <li id="dosomething">something</li>      <li id="buysomething">something</li>      <li id="gosomething">something</li></ul>

按照传统做法,需要像下面这样为它们添加3个事件处理程序。使用事件委托,只需要在DOM树中尽量最高的层次上添加一个事件处理程序,例如:

        var list =document.getElementById("myList");        EventUtil.addHandler(list,"click",function(event){            event = EventUtil.getEvent(event);            var target = EventUtil.getTarget(event);            switch(target.id){                case "dosomething":                    document.title = "I changed the document`s title";                    break;                case "gosomething":                    location.href = "http://www.baidu.com";                    break;                case "buysomething":                    alert("buy sth");                    break;            }        })
在这段代码中,我们使用事件委托只为<ul>元素添加了一个onclick事件处理程序。由于所有列表项都是这个元素的子节点,而且他们的事件会冒泡,所以单击事件最终会被这个函数处理,可以通过检测id属性来决定采取适当的操作。这种方法对用户来说最终的结果相同,但是只取得了一个DOM元素,只添加了一个事件处理程序,占用的内存更少。

--------------------------------------------------------------------------------------------以下摘自凌云之翼,如侵删------------------------------------------------------------------------------------------------------

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

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

复制代码
<input type="button" name="" id="btn" value="添加" />    <ul id="ul1">        <li>111</li>        <li>222</li>        <li>333</li>        <li>444</li>    </ul>
复制代码

 

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

 

复制代码
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);            };        }
复制代码

 

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

复制代码
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 ();            };        }
复制代码

 

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

复制代码
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操作,这才是事件委托的精髓所在。