DOM 事件模型
点击、滚动、触摸、拖拽……这些用户与 web 页面交互的手段都可以称之为「事件」,了解 JavaScript 的事件机制,无论是对优化一些用户交互亦或是处理线上 BUG 都会有很大的帮助。
DOM 0 级
DOM 事件分为两种 1.行内事件:在标签中写事件 2.普通事件:元素.on 事件名=函数
1.行内
<input type="button" id="btn" value="按钮" onclick="alert('阿巴阿巴')" />
2.普通事件
document.querySelector('div').onclick = function () {
alert('阿巴阿巴');
};
DOM 1 级
1998 年 DOM1 级规范称为 W3C 的推荐标准。
DOM1 级为基本文档结构及查询提供了接口, DOM1 级的目标主要是映射文档的结构。 IE、Firefox、Safari、Chrome 和 Opera 都非常完善地实现了 DOM。
DOM 2 级
定义了 addEventListener 和 removeEventListener 用来绑定和解绑事件。
方法有三个参数: 1.事件名(不需要写 on) 2.事件回调函数 3.false/ true:事件冒泡 / 事件捕获时执行回调函数
DOM 3 级
DOM3 级事件 在 DOM2 级事件的基础上添加了更多的事件类型,全部类型如下:
UI事件:当用户与页面上的元素交互时触发,如:load、scroll焦点事件:当元素获得或失去焦点时触发,如:blur、focus鼠标事件:当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup滚轮事件:当使用鼠标滚轮或类似设备时触发,如:mousewheel文本事件:当在文档中输入文本时触发,如:textInput键盘事件:当用户通过键盘在页面上执行操作时触发,如:keydown、keypress合成事件,当为 IME(输入法编辑器)输入字符时触发,如:compositionstart变动事件,当底层 DOM 结构发生变化时触发,如:DOMsubtreeModified
同时 DOM3 级事件也允许使用者自定义一些事件。
IE 事件模型
IE 中的事件模型比较特殊,事件监听的绑定与移除并不是使用
addEventListener和removeEventListener
//IE中使用attachEvent绑定事件
document.querySelector('div').attachEvent('click', function () {
alert('阿巴阿巴');
});
DOM 事件机制
演示 🎨
<div class="box">
<div class="item1">
<div class="item2">
<div class="item3">item3</div>
item2
</div>
item1
</div>
box
</div>
事件冒泡示例
var box = document.querySelector('.box');
var item1 = document.querySelector('.item1');
var item2 = document.querySelector('.item2');
var item3 = document.querySelector('.item3');
box.addEventListener('click', function () {
console.log('我是box');
});
item1.addEventListener('click', function () {
console.log('我是item1');
});
item2.addEventListener('click', function () {
console.log('我是item2');
});
item3.addEventListener('click', function () {
console.log('我是item3');
});
点击 item3 时,由内到外一次响应事件函数 结果如下图所示
事件捕获示例
var box = document.querySelector('.box');
var item1 = document.querySelector('.item1');
var item2 = document.querySelector('.item2');
var item3 = document.querySelector('.item3');
box.addEventListener(
'click',
function () {
console.log('我是box');
},
true
);
item1.addEventListener(
'click',
function () {
console.log('我是item1');
},
true
);
item2.addEventListener(
'click',
function () {
console.log('我是item2');
},
true
);
item3.addEventListener(
'click',
function () {
console.log('我是item3');
},
true
);
那么捕获与冒泡同时存在,执行顺序是怎样的呢?
box.addEventListener('click', function () {
console.log('我是box');
});
item1.addEventListener(
'click',
function () {
console.log('我是item1,我设置了true,事件捕获时就触发');
},
true
);
item2.addEventListener('click', function () {
console.log('我是item2');
});
item3.addEventListener(
'click',
function () {
console.log('我是item3,我设置了true,事件捕获时就触发');
},
true
);
答案:若捕获阶段发现有 true 的则执行,所以执行顺序:先捕获后冒泡。
DOM2 级事件模型规定事件流包括三个阶段:事件捕获阶段、目标阶段、事件冒泡阶段
事件捕获阶段
捕获阶段是指事件响应从最外层的 Window 开始,逐级向内层前进,直到具体事件目标元素。在捕获阶段,默认不会处理响应元素的注册的事件。 注意 📢
- 若
addEventListener中第三个参数为flase(默认为 false):在捕获阶段不会处理响应元素的注册的事件。 - 若
addEventListener中第三个参数为true(默认为 false):在捕获阶段处理响应元素的注册的事件
目标阶段
到达目标事件位置(事发地),触发事件;
冒泡阶段
再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象。 注意 📢
- 若
addEventListener中第三个参数为flase(默认为 false):在冒泡阶段处理响应元素的注册的事件。 - 若
addEventListener中第三个参数为true(默认为 false):在冒泡阶段不会处理响应元素的注册的事件
阻止冒泡
若我们想要阻止某个元素之后的冒泡事件(阻止冒泡事件的继续传播)我们可以给元素设置event.stopPropagation()
item2.addEventListener('click', function (event) {
console.log('我是item2');
event.stopPropagation(); //event代表事件对象
});
成功阻止了后续 box 的冒泡事件执行
阻止默认行为
- a 标签的跳转
- 导航(二级导航)
- submit 按钮的提交
- 右键菜单(web 应用程序里,在线 Word)
- 文本框的输入
- ...
诸如以上这些元素都拥有自带的事件处理行为,都属于元素的默认行为。
a 标签默认行为演示
<a href="http://www.csdn.net">点击跳转CSDN</a>
添加event.preventDefault()后
var a = document.querySelector('a');
a.addEventListener('click', function (e) {
e.preventDefault();
console.log('我阻止了a标签的默认跳转行为');
});
执行结果: