具体见:https://github.com/febobo/web-interview
6.事件模型
①事件与事件流
事件(Events)
事件是指页面中发生的交互行为,比如用户点击按钮、键盘输入、鼠标移动等。在js中,可以通过事件来触发相应的操作,例如执行函数、改变样式等。常见的事件包括点击事件(click
)、键盘事件(keypress、keydown、keyup
)、鼠标事件(mouseover、mouseout、mousedown、mouseup
)等
事件流(Event FLow)
事件流描述了事件在页面中传播和被处理的顺序。在DOM树中,事件流可以分为冒泡阶段和捕获阶段。
-
事件捕获阶段(Capturing Phase):事件从最外层的元素开始向最具体的元素传播。即事件从document对象开始,逐级向下传播到目标元素。
-
目标阶段(Target Phase):事件到达目标元素本身。
-
事件冒泡阶段(Bubbing Phase):事件从目标元素开始向上传播,逐级向上传播到document对象。
<html>
<body>
<div id="d1">
<button id="btn1">click me</button>
</div>
</body>
</html>
//冒泡阶段
var button = document.getElementById('btn1')
var div = document.querySelector('#d1')
div.onclick = function () {
console.log('2. this is div');
};
document.body.onclick = function () {
console.log('3.this is body');
};
document.onclick = function () {
console.log('4.this is document');
};
window.onclick = function () {
console.log('5.this is window');
};
button.onclick = function () {
console.log('1.this is button');
};
冒泡阶段结果:
1.this is button
2.this is div
3.this is body
4.this is document
5.this is window
//捕获阶段
var button = document.getElementById('btn1')
var div = document.querySelector('#d1')
div.addEventListener('click', function () {
console.log('2. this is div');
}, true);
document.body.addEventListener('click', function () {
console.log('3.this is body');
}, true);
document.addEventListener('click', function () {
console.log('4.this is document');
}, true);
window.addEventListener('click', function () {
console.log('5.this is window');
}, true);
button.addEventListener('click', function () {
console.log('1.this is button');
}, true);
结果与冒泡相反。
②事件模型
事件模型可以分为三种:
- 原始事件模型(DOM0级)
- 标准事件模型(DOM2级)
- IE事件模型(基本不用)
(1)原始事件模型
事件绑定监听函数比较简单, 有两种方式:
- HTML代码中直接绑定
<input type="button" onclick="fun()">
- 通过
JS
代码绑定
var btn = document.getElementById('.btn');
btn.onclick = fun;
【特性】
- 绑定速度快
DOM0
级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行
- 只支持冒泡,不支持捕获
- 同一个类型的事件只能绑定一次
<input type="button" id="btn" onclick="fun1()">
var btn = document.getElementById('.btn');
btn.onclick = fun2;
如上,当希望为同一个元素绑定多个同类型事件的时候(上面的这个btn
元素绑定2个点击事件),是不被允许的,后绑定的事件会覆盖之前的事件
删除 DOM0
级事件处理程序只要将对应事件属性置为null
即可
btn.onclick = null;
(2)标准事件模型
通过 addEventListener
方法来注册事件处理程序,并通过第三个参数来指定事件处理程序是在捕获阶段执行还是在冒泡阶段执行。当第三个参数为 true
时,事件处理程序在捕获阶段执行;当为 false
或省略时,默认在冒泡阶段执行。
事件绑定监听函数的方式如下:
addEventListener(eventType, handler, useCapture)
事件移除监听函数的方式如下:
removeEventListener(eventType, handler, useCapture)
参数如下:
eventType
指定事件类型(不要加on)handler
是事件处理函数useCapture
是一个boolean
用于指定是否在捕获阶段进行处理,一般设置为false
与IE浏览器保持一致
【特性】
- 可以在一个
DOM
元素上绑定多个事件处理器,各自并不会冲突
btn.addEventListener(‘click’, showMessage1, false);
btn.addEventListener(‘click’, showMessage2, false);
btn.addEventListener(‘click’, showMessage3, false);
- 执行时机
当第三个参数(useCapture
)设置为true
就在捕获过程中执行,反之在冒泡过程中执行处理函数
下面举个例子:
<div id='div'>
<p id='p'>
<span id='span'>Click Me!</span>
</p >
</div>
设置点击事件
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);
上述使用了eventPhase
,返回一个代表当前执行阶段的整数值。1为捕获阶段、2为事件对象触发阶段、3为冒泡阶段
点击Click Me!
,输出如下
P 3
DIV 3
可以看到,p
和div
都是在冒泡阶段响应了事件,由于冒泡的特性,裹在里层的p
率先做出响应
如果把第三个参数都改为true
div.addEventListener('click', onClickFn, true);
p.addEventListener('click', onClickFn, true);
输出如下
DIV 1
P 1
两者都是在捕获阶段响应事件,所以div
比p
标签先做出响应