JavaScript 事件机制详解

138 阅读3分钟

JavaScript 事件机制

JavaScript 事件是 Web 交互的核心,它允许浏览器对用户操作做出响应。事件代表了文档或浏览器窗口中发生的特定交互瞬间,比如点击、滚动、键盘输入等。

一、DOM 事件级别

DOM 0 级事件

DOM0级事件是之间在元素属性上绑定事件,这种方式代码耦合度搞HTML、JS 混杂,不利于代码维护,并且只能绑定一个处理函数。

违背"关注点分离"原则(HTML/CSS/JS 应各司其职)

element.onclick = function() { 
  console.log('Clicked'); 
};

DOM 2 级事件(推荐)

DOM2 级事件是添加一个事件监听器,这种方式可以精确控制事件触发阶段(捕获/冒泡),符合现代Web开发规范

// 事件绑定
element.addEventListener('click', function() {
  console.log('click');
});

// 事件解绑
element.removeEventListener('click', handlerFunction);

二、addEventListener 详解

基本语法

addEventListener(type, listener);
addEventListener(type, listener, options);
addEventListener(type, listener, useCapture);

参数说明:第一个参数type为事件类型如('click'、'DOMContentLoaded'等);第二个参数是listener:事件监听器(不是简单的回调函数);第三个参数是useCapture指定事件执行的顺序,这是给布尔值默认是false(表示冒泡阶段,事件从内向外传播)若设置为true则表示捕获阶段(事件从外向内传播)

{
  capture: Boolean, // 是否在捕获阶段触发
  once: Boolean,    // 是否只触发一次
  passive: Boolean  // 是否不会调用preventDefault()
}

三、事件流与执行顺序

当父元素中嵌套了子元素,前两者都有相同的事件触发,这时两者事件触发的顺序取决于事件注册时的第三参数。

事件三个阶段

  • 捕获阶段:由window——document——...——目标元素

    在浏览器中捕获事件发生的位置,然后事件首先从最外层的 window 对象开始,逐级向下传递到目标元素的每一层祖先,最后到达实际触发事件的元素。

  • 目标阶段:到达实际触发事件的元素

  • 冒泡阶段:从目标元素 → ... → document → window

    事件从目标元素开始,逐级向上传递直到doucment、window

嵌套元素事件执行示例

<div id="parent">
  <div id="child"></div>
</div>

<script>
const parent = document.getElementById("parent");
const child = document.getElementById("child");

// 默认冒泡阶段
parent.addEventListener("click", () => console.log("parent 冒泡")); 
child.addEventListener("click", () => console.log("child 冒泡"));

// 捕获阶段
parent.addEventListener("click", () => console.log("parent 捕获"), true);
child.addEventListener("click", () => console.log("child 捕获"), true);
</script>

点击child时的输出顺序:

parent 捕获
child 捕获
child 冒泡
parent 冒泡

关键概念:event.target始终指向实际触发事件的元素

四、事件委托机制

事件委托机制是利用事件冒泡特性,当某个DOM元素触发事件后,该事件会逐级向上传递。因此我们可以理由这个特性在父元素上统一监听事件,再利用event.target指向事件实际发生元素来对子元素进行操作。

    <div id="container">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
        <div class="item">4</div>
        <div class="item">5</div>
    </div>
    <script>
        document.getElementById('container').addEventListener('click', function(e) {
            console.log(e.target.textContent)
        })
    </script>

与传统帮定优势对比,这种方式所需要的内存小(只需要注册单个监听器,传统方式选哟注册多个),代码量小,可维护性好。