Skip to content

事件的捕获和冒泡机制

捕获过程:window->document->body->div->text

冒泡过程:text->div->body->document->window

addEventListener

addEventListener方法用来为一个特定的元素绑定一个事件处理函数,共有三个参数:

js
 element.addEventListener(event, function, useCapture)
  • event

    必填项,字符串类型,表示绑定的是哪种事件(注意把所有的on去掉,比如onclick,改为click,其它同理),绑定类型参考 绑定事件参考手册

  • function

    可选填,事件处理函数,事件对象会作为第一个参数传入函数。事件对象的类型取决于特定的事件。比如click事件属于MouseEvent(鼠标事件)对象

  • useCapture

    Boolean类型,true或false(默认为false)。

    true表示事件在捕获阶段执行。

    false表示事件在冒泡阶段执行。

什么是事件冒泡

假如有一层嵌套的div,每一层div上都添加了点击事件,事件会从最里面往外触发,这就是事件冒泡。

如下面的代码:outer->middle->inner->button,所有元素添加的都是冒泡事件,useCapture为false

当点击button时,事件触发会从里往外冒,依次打印bubble button->bubble inner->bubble middle->bubble outer

同理点击inner时,依次打印bubble inner->bubble middle->bubble outer

点击middle时,依次打印bubble middle->bubble outer

点击outer时,打印bubble outer

html
<style>
    div {
        padding: 30px;
    }

    .outer {
        background-color: pink;
    }

    .middle {
        background-color: green;
    }

    .inner {
        background-color: orange;
    }
</style>
<body>
    <div class="outer">
        <div class="middle">
            <div class="inner">
                <button>click me</button>
            </div>
        </div>
    </div>

    <script type="module">
        const $ = (selector)=>{
            return document.querySelector(selector)
        }

        // 冒泡
        $('.outer').addEventListener('click',function(e){
            console.log('bubble outer');
        }, false)

        $('.middle').addEventListener('click',function(e){
            console.log('bubble middle');
        }, false)
        $('.inner').addEventListener('click',function(e){
            console.log('bubble inner');
        }, false)

        $('button').addEventListener('click',function(e){
            console.log('bubble button');
        }, false)
    </script>
</body>

什么是事件捕获

假如有一层嵌套的div,每一层div上都添加了点击事件,事件会从最外面往里触发,这就是事件捕获。

如下面的代码:outer->middle->inner->button,所有元素添加的都是捕获事件,useCapture为true

当点击outer时,事件触发会从外往里触发,依次打印capture outer->capture middle->capture inner->capture button

同理点击middle时,依次打印capture middle->capture inner->capture button

点击inner时,依次打印capture inner->capture button

点击button时,打印``capture button`

html
<style>
    div {
        padding: 30px;
    }

    .outer {
        background-color: pink;
    }

    .middle {
        background-color: green;
    }

    .inner {
        background-color: orange;
    }
</style>
<div class="outer">
    <div class="middle">
        <div class="inner">
            <button>click me</button>
        </div>
    </div>
</div>

<script type="module">
    const $ = (selector)=>{
        return document.querySelector(selector)
    }

    // 捕获
    $('.outer').addEventListener('click',function(e){
        console.log('capture outer');
    }, true)

    $('.middle').addEventListener('click',function(e){
        console.log('capture middle');
    }, true)
    $('.inner').addEventListener('click',function(e){
        console.log('capture inner');
    }, true)

    $('button').addEventListener('click',function(e){
        console.log('capture button');
    }, true)
</script>
</body>

同时都存在时,先触发哪一个

先触发捕获,后触发冒泡

e.targete.currentTarget的区别

e.target:是自己实际点击的那个div

e.currentTarget:是绑定事件函数后,因捕获或者冒泡机制而触发的那个div

所以有个很巧妙的判断,e.target===e.currentTarget,表示是自嗨型,自己的事件,点击的自己,触发也是自己的事件函数。当不相等时,说明事件是通过冒泡或者捕获触发的。

阻止事件冒泡

e.stopPropagation()

阻止默认行为

e.preventDefault()

事件委托

假如ul里有100个li,每个li都需要绑定点击事件,常规做法是遍历每个li,然后绑定点击事件。

这种做法在li非常少的情况下还行,当有非常多的li时,就不可取了。

所以这时可以将事件绑定到父级ul身上,根据事件冒泡机制,点击li时,仍然可以将点击事件冒泡给ul,触发父级ul的点击事件。然后通过e.target找到实际点击的元素,就可以判断出来是哪一个li。

常见事件

鼠标事件

  • click:用户点击元素。
  • dblclick:用户双击元素。
  • mousedown:用户按下鼠标按钮。
  • mouseup:用户释放鼠标按钮。
  • mousemove:鼠标在元素上移动。
  • mouseenter:鼠标进入元素边界。
  • mouseleave:鼠标离开元素边界。
  • mouseover:鼠标移入元素或其子元素。
  • mouseout:鼠标移出元素或其子元素。
  • contextmenu:用户触发上下文菜单(通常是通过鼠标右键)。

键盘事件

  • keydown:用户按下键盘上的键。
  • keyup:用户释放键盘上的键。
  • keypress:用户按下键盘上的键(已废弃,不建议使用)。

焦点事件

  • focus:元素获得焦点。
  • blur:元素失去焦点。
  • focusin:元素即将获得焦点。
  • focusout:元素即将失去焦点。

表单事件

  • change:元素的值发生变化。
  • input:用户输入数据时触发。
  • submit:表单提交。
  • reset:表单重置。

触摸事件

  • touchstart:用户触摸屏幕。
  • touchmove:用户手指在屏幕上移动。
  • touchend:用户手指从屏幕上抬起。
  • touchcancel:触摸被中断。

UI事件

  • resize:窗口或框架被调整大小。
  • scroll:元素滚动。

进度事件

  • load:对象加载完成。
  • unload:对象正在被卸载。
  • beforeunload:即将卸载页面。
  • error:在加载文档或图像时发生错误。
  • abort:对象加载被中止。

资源事件

  • loadstart:开始加载。
  • progress:加载过程中。
  • loadend:加载结束。

动画和过渡事件

  • animationstart:CSS动画开始。
  • animationend:CSS动画结束。
  • animationiteration:CSS动画重复。
  • transitionend:CSS过渡完成。

其他事件

  • drag:元素被拖动。
  • drop:拖放操作结束。
  • select:用户选择文本。
  • wheel:鼠标滚轮在元素上滚动。