JavaScript - 事件委托(事件捕获和事件冒泡)

<!--
事件委托:
所有 li 的点击事件委托给document元素,
ul 中可随时添加 li 元素,都会自动冒泡触发 document 的 click 事件,
打印出点击的 li 的相关数据。
在 jQuery 中写法:$(document).on('click', 'li', function (e) {})
-->
<ul>
    <li class="a1">00001</li>
    <li class="a2">00002</li>
    <li class="a3">00003</li>
    <li class="a4">00004</li>
    <li class="a5">00005</li>
</ul>
<script>
    document.addEventListener('click',function (e) {
        var eve = e || window.event;   // IE9和IE10兼容event写法
        if (eve.target.nodeName === "LI"){
            var el = eve.target;
            console.log(el.innerHTML);   // 点哪个li打印哪个li的innerHTML
            console.log(el.getAttribute('class'));  // 点哪个li打印哪个li的class
        }
    })
</script>
  1. 事件委托(事件代理)的作用?
  • 支持为同一个DOM元素注册多个同类型事件
  • 可将事件分成事件捕获和事件冒泡机制
  1. 注册多个事件
<div id="div1"></div>

window.onload = function(){
    let div1 = document.getElementById('div1');
    div1.onclick = function(){
        console.log('打印第一次')
    }
    div1.onclick = function(){
        console.log('打印第二次')
    }
}
// 运行结果是:“打印第二次”
// 可以看到第二个点击注册事件覆盖了第一个注册事件,只执行了console.log('打印第二次');
<div id="div1"></div>

window.onload = function(){
    let div1 = document.getElementById('div1');
    div1.addEventListener('click',function(){
        console.log('打印第一次')
    })
    div1.addEventListener('click',function(){
        console.log('打印第二次')
    })
}
// 运行结果是:“打印第一次   打印第二次”
// 可以看到两个注册事件都成功触发了。 useCapture是事件委托的关键,我们后面详解
  1. 事件捕获和事件冒泡机制
  • 事件捕获
    当一个事件触发后,从Window对象触发,不断经过下级节点,直到目标节点。在事件到达目标节点之前的过程就是捕获阶段。所有经过的节点,都会触发对应的事件
  • 事件冒泡
    当事件到达目标节点后,会沿着捕获阶段的路线原路返回。同样,所有经过的节点,都会触发对应的事件


    image.png
  • 举例
//当useCapture为默认false时,为事件冒泡
<body>
    <div id="div1"></div>
</body>

window.onload = function(){
    let body = document.querySelector('body');
    let div1 = document.getElementById('div1');
    body.addEventListener('click',function(){
        console.log('打印body')
    })
    div1.addEventListener('click',function(){
        console.log('打印div1')
    })
}

//结果:打印div1  打印body
//当useCapture为true时,为事件捕获
<body>
    <div id="div1"></div>
</body>

window.onload = function(){
    let body = document.querySelector('body');
    let div1 = document.getElementById('div1');
    body.addEventListener('click',function(){
        console.log('打印body')
    },true)
    div1.addEventListener('click',function(){
        console.log('打印div1')
    })
}

//结果:打印body   打印div1
  1. 事件委托的优点
  • 提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
  • 动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。
  1. 事件委托和新增节点绑定事件的关系
<script>
    window.onload = function(){
        let div = document.getElementById('div');
        
        div.addEventListener('click',function(e){
            console.log(e.target)
        })
        
        let div3 = document.createElement('div');
        div3.setAttribute('class','div3')
        div3.innerHTML = 'div3';
        div.appendChild(div3)
    }
</script>


<body>
    <div id="div">
        <div class="div1">div1</div>
        <div class="div2">div2</div>
    </div>
</body>
image.png
  • 虽然没有给div1和div2添加点击事件,但是无论是点击div1还是div2,都会打印当前节点。因为其父级绑定了点击事件,点击div1后冒泡上去的时候,执行父级的事件。
  • 这样无论后代新增了多少个节点,一样具有这个点击事件的功能。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。