Javascript 事件冒泡、事件捕获、事件代理

372 阅读3分钟

2019开工荒了两天,赶紧开始!

为什么写事件代理、冒泡、捕获,首先冒泡和捕获是js事件的核心基础,事件代理原理来自冒泡和捕获。

此文章略过标准浏览器和非标准浏览器的事件流讲解,原因很简单我们现在已经幸福了,已经不考虑IE6、7、8了

直接说现代浏览器事件流,用两张图看看什么是冒泡 什么是捕获,其实从字面意思大概能看出 一个是向外一个是向内。

事件冒泡

事件捕获

标准事件流

1、捕获阶段 (先从最外层向内查找) 2、目标阶段(找到事件元(当前点击的dom)) 3、冒泡阶段(向上冒泡传递事件)

事件冒泡

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>冒泡</title>
</head>
<style>
    * {
        margin: 0;
        padding: 0;
    }
    
    div {
        padding: 30px;
    }
    
    .div1 {
        background: red
    }
    
    .div2 {
        background: blueviolet
    }
    
    .div3 {
        background: yellowgreen
    }
</style>

<body>
    <div class="div1">
        父
        <div class="div2">
            子
            <div class="div3">
                孙
            </div>
        </div>
    </div>
    <script>
       // javascript事件绑定addEventListener接收三个参数,
       //  1、事件名称字符串且不带on
       //  2、回调函数
       //  3、事件流方式(默认为冒泡(false),捕获为true)
        window.onload = function() {
            document.querySelector('.div1').addEventListener('click', function() {
                console.log('点击div1')
            }, false)
            document.querySelector('.div2').addEventListener('click', function() {
                console.log('点击div2')
            }, false)
            document.querySelector('.div3').addEventListener('click', function() {
                console.log('点击div3')
            }, false)
        }
    </script>
</body>

</html>

先演示下冒泡

事件冒泡

事件捕获

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>冒泡</title>
</head>
<style>
    * {
        margin: 0;
        padding: 0;
    }
    
    div {
        padding: 30px;
    }
    
    .div1 {
        background: red
    }
    
    .div2 {
        background: blueviolet
    }
    
    .div3 {
        background: yellowgreen
    }
</style>

<body>
    <div class="div1">
        父
        <div class="div2">
            子
            <div class="div3">
                孙
            </div>
        </div>
    </div>
    <script>
        window.onload = function() {
            document.querySelector('.div1').addEventListener('click', function(e) {
                console.log('点击父元素')
            }, true)
            document.querySelector('.div2').addEventListener('click', function(e) {
                console.log('点击子元素')
            }, true)
            document.querySelector('.div3').addEventListener('click', function(e) {
                console.log('点击孙子元素')
            }, true)
        }
    </script>
</body>

</html>

看看效果

事件捕获

事件委托

我理解的事件委托的好处有两点 1、减少事件绑定次数 2、可以给未知元素绑定事件(例如动态渲染的List)

其原理就是利用事件冒泡向外传递的特性,下面代码解析一下: 同样忽略低版本浏览器获取当前target兼容性问题

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>冒泡</title>
</head>
<style>
    * {
        margin: 0;
        padding: 0;
    }
    
    div {
        padding: 30px;
        border: 1px solid red
    }
    
    div span {
        display: inline-block;
        padding: 10px;
        border: 1px solid blueviolet
    }
</style>

<body>
    <div class="div1">
        <span>1</span>
        <span>2</span>
        <span>3</span>
        <span>4</span>
    </div>
    <script>
        window.onload = function() {
            document.querySelector('.div1').addEventListener('click', function(e) {
                //回调函数e为事件对象,同伙事件对象可以获取当前点击dom
                console.log(e.target)
                //获取到当前事件源(dom)后再去搞一些你想搞的事情就ok了

                //搞事情代码
            }, false)

        }
    </script>
</body>

</html>

老规矩,看看效果

事件委托

最后顺便说一下事件对象功能很全的,看下图能获取到很多当前dom的周边,可以搞好多其它的事情。

事件对象

感谢阅读,欢迎吐槽!谢谢!