目录

🍎 JavaScript 事件模型

相关问题:

  • JavaScript 中对事件模型的理解。

# 概念:事件与事件流

JavaScript 中的事件,理解为在 HTML 文档或者浏览器中发生的交互操作。常见的事件有 加载事件、鼠标事件、自定义事件。

DOM 是一个树结构,如果父子节点绑定事件时,当触发子节点时,存在事件的顺序问题。这就涉及事件流的概念。

事件流都会经历三个阶段:

  • 事件捕获阶段
  • 目标阶段
  • 冒泡阶段

3e9a6450-74cf-11eb-85f6-6fac77c0c9b3

# 概念:事件模型

事件模型可以分为三种类型:

  • 原始事件模型(DOM 0 级)
  • 标准事件模型(DOM 2 级)
  • IE 事件模型(基本不用)

# 原始事件模型

特点:

  • 事件绑定速度快;
  • 只支持冒泡,不支持捕获;
  • 同一类型的事件只能绑定一次;

🌰 例子 / 事件绑定监听函数的方式:

在 HTML 中直接绑定:

<input type="button" onclick="fun()">
1

通过 JavaScript 代码绑定:

var btn = document.getElementById("#btn")
btn.onclick = function() {
  ...
}
1
2
3
4

🌰 例子 / 同类型的事件只能绑定一次:

<input type="button" id="btn" onclick="fun1()">
1
var btn = document.getElementById('.btn');
btn.onclick = fun2;
1
2

这里为 btn 绑定了两个同类型的(点击)事件,后面绑定的事件会覆盖之前的事件。

🌰 例子 / 删除之间绑定的事件:

btn.onclick = null
1

# 标准事件模型

该事件模型中,一次事件共有三个过程:

  • 事件捕获阶段:事件从 document 一直向下传播到目标元素,一次检查经过的节点是否绑定了事件监听函数,如果有则执行。
  • 事件处理阶段:事件到达目标元素,触发目标元素的监听函数。
  • 事件冒泡阶段:事件从目标元素冒泡到 document ,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。

特点:

  • 可以在一个 DOM 元素上绑定多个事件处理器,各自不会冲突;
  • 执行实时机:当 addEventListener() 第三个参数 useCapture 设置为 true 就在捕获过程中执行,反之在冒泡过程中执行处理函数;

🌰 例子 / 绑定监听函数和移除监听函数:

addEventListener(eventType, handler, useCapture)
1
removeEventListener(eventType, handler, useCapture)
1

🌰 例子 / 绑定点击事件:

var btn = document.getElementById('.btn');
btn.addEventListener(‘click’, showMessage, false);
btn.removeEventListener(‘click’, showMessage, false);
1
2
3

绑定多个点击事件:

btn.addEventListener(‘click’, showMessage1, false);
btn.addEventListener(‘click’, showMessage2, false);
btn.addEventListener(‘click’, showMessage3, false);
1
2
3

🌰 例子 / 设置事件的执行时机:

<div id='div'>
    <p id='p'>
        <span id='span'>Click Me!</span>
    </p >
</div>
1
2
3
4
5

设置 useCapturefalse

var div = document.getElementById('div');
var p = document.getElementById('p');

function onClickFn (event) {
    var tagName = event.currentTarget.tagName;
    var phase = event.eventPhase;
    console.log(tagName, phase);
}

div.addEventListener('click', onClickFn, false);
p.addEventListener('click', onClickFn, false);
1
2
3
4
5
6
7
8
9
10
11

使用了 eventPhase ,返回一个代表当前执行阶段的整数值。1 为捕获阶段、2 为事件对象触发阶段、3 为冒泡阶段。

此时, pdiv 都在冒泡阶段响应了事件,因为冒泡的特性,所以 p 率先做出响应。

如果把 useCapture 设置为 true ,输出的结果应该为:

DIV 1
P 1
1
2

意味着两者都是在捕获阶段响应事件,所以 divp 先做出响应。

📢 上次更新: 2022/09/02, 10:18:16