天天看点

DOM事件流详解事件流相关概念  事件捕获事件冒泡事件委托

目录

        事件流相关概念  

        事件捕获

        事件冒泡

        事件委托

        优点

        缺点

事件流相关概念  

        事件流描述的是从页面中接受事件的顺序

        DOM事件流包括三个阶段:

        1.事件捕获阶段:事件从window对象开始触发,该阶段主要捕获截取事件

        2.处于目标阶段:该阶段具有双重范围--捕获阶段结束、冒泡阶段开始

        3.事件冒泡阶段:将目标元素绑定事件执行结果返回给浏览器

DOM事件流详解事件流相关概念  事件捕获事件冒泡事件委托

事件捕获

        该概念由网景公司提出。事件响应从最外层window开始,逐级向内层传播,直到具体的事件目标元素。

        在上一篇总结事件处理的博客中,我们有了解到使用事件监听方式给元素注册事件处理函数,其中第三个可选参数capture,默认false(事件冒泡阶段处理),可填true(事件捕获阶段处理),通过这个参数我们就可以设置事件处理阶段采用什么方式。现在我们可以通过代码测试来看看事件捕获与事件冒泡之间的区别:

<div>
        <p>
            <button>点击</button>
        </p>
    </div>
    <script>
        var div = document.querySelector('div');
        var p = document.querySelector('p');
        var button = document.querySelector('button');
        //注册捕获事件监听器
        div.addEventListener('click',function(e){
            console.log("div元素");
        },true);
        p.addEventListener('click',function(e){
            console.log("p元素");
        },true);
        button.addEventListener('click',function(e){
            console.log("button元素");
        },true);
    </script>
           

        点击按钮后console调试接口中各个输出顺序如下:可见是由外到内逐个捕获 

DOM事件流详解事件流相关概念  事件捕获事件冒泡事件委托

事件冒泡

        该概念由微软公司提出,事件传播顺序与事件捕获相反,是从事件按开始的具体元素,一级级往上传播,直至返回给window。

        例如:

<div>
        <p>
            <button>点击</button>
        </p>
    </div>
    <script>
        var div = document.querySelector('div');
        var p = document.querySelector('p');
        var button = document.querySelector('button');
        //注册冒泡事件监听器
        div.addEventListener('click',function(e){
            console.log("div元素");
        },false);
        p.addEventListener('click',function(e){
            console.log("p元素");
        },false);
        button.addEventListener('click',function(e){
            console.log("button元素");
        },false);
    </script>
           

        点击按钮后console调试接口中各个输出顺序如下:可见是由内到外逐个捕获  

DOM事件流详解事件流相关概念  事件捕获事件冒泡事件委托

事件委托

        事件委托,也称事件代理,利用它将事件绑定给父级元素或者更高级元素,让处理代码在父级元素或者更高级元素中执行,这样只指定一个事件处理程序,就可以管理某一类型的所有事件,提高程序运行效率。举个例子:一个班的教材,每个人自己去教材科领书会很繁杂,很导致很多人排队进度慢,利用事件委托,让班主任领回全班的书再依次分发给同学们,这样就会提高效率,减少不必要的进程。

        例如,我们想给每个<li>绑定单击事件,常规方法是使用遍历给每个<li>绑定一个单击事件

<ul>
        <li>content1</li>
        <li>content2</li>
        <li>content3</li>
        <li>content4</li>
        <li>content5</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        var lis = ul.querySelectorAll('li');
        for(var i=0;i<lis.length;i++){
            lis[i].onclick = function(){
                console.log(this.innerText);
            }
        }
    </script>
           

        这个方法在列表项少的时候可以使用,但是当列表项很多的时候,例如成千上万个<li>,就会导致性能降低。这个时候我们利用事件委托,只需要给<ul>绑定一个事件:

<ul>
        <li>content1</li>
        <li>content2</li>
        <li>content3</li>
        <li>content4</li>
        <li>content5</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        var lis = ul.querySelectorAll('li');
        ul.addEventListener("click",function(e){
            var e = e || window.event;  //兼容性处理
            if(e.target.nodeName.toLowerCase() === 'li'){
                console.log(e.target.innerText);
            }},false);
    </script>
           

        它的原理是利用了事件冒泡机制,当点击<li>,会向上冒泡到<ul>,然后就会触发绑定在<ul>上的事件,再利用event.target属性找到触发时间的节点,做出相应动作,就可以达到相同的效果。

        使用事件代理不仅可以将多个事件处理函数减少为一个,还可以针对不同的元素做出不同的处理方法。例如上例中,若列表元素中添加其他元素节点,我们可以直接修改事件代里的事件处理函数,用此来代替循环给元素绑定事件。

        综上我们可以总结一下事件委托的优缺点:

优点

        1.减少事件注册,节省内存占用

        2.动态绑定事件,当新增子对象时无需再次对其绑定

缺点

        1.如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失

        2.事件冒泡过程也需要耗时,越靠近顶层,事件传播链越长,耗时越长(所以使用事件委托时,不是把事件委托给的元素越靠近顶层越好,需要根据代码要实现的效果均衡考虑)

继续阅读