本文主要介绍:
- DOM 事件级别
- DOM 事件模型
- DOM 事件委托
- DOM 事件级别 DOM 级别可以分为四个级别:DOM 0 级、DOM 1 级、DOM 2 级和 DOM 3 级。 而 DOM 事件分为三个级别:DOM 0 级事件处理、DOM 2 级事件处理和 DOM 3 级事件处理。
由于 DOM 1 级中没有事件的相关内容,所以没有 DOM 1 级事件。
1.1 DOM 0 级事件
在了解 DOM 0 级事件之前,我们有必要先了解下 HTML 事件处理程序,也是最早的这一种的事件处理方式,代码如下:
<button type="button" onclick="showFn()"></button>
<script>
function showFn() {
alert('Hello World');
}
</script>
以上代码通过直接在 HTML 代码里定义了一个 onclick 的属性触发 showFn 方法,这样的事件处理程序最大的缺点就是 HTML 与 JS 强耦合,一旦需要修改函数名就得修改两个地方。当然其优点是不需要操作 DOM 来完成事件的绑定。 而 DOM 0 级事件就是将一个函数赋值给一个事件处理属性,比如:
<button id="btn" type="button"></button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function() {
alert('Hello World');
}
// btn.onclick = null; 解绑事件
</script>
以上代码给 button 定义了一个 id,通过 JS 获取到了这个 id 的按钮,并将一个函数赋值给了一个事件处理属性 onclick,这样的方法便是 DOM 0 级处理事件。另外可以通过给事件处理属性赋值 null 来解绑事件。
小结
el.onclick=function(){} DOM 0 级事件处理程序的事件在冒泡阶段执行。 DOM 0 级事件处理程序的缺点在于无法为同一个元素绑定多个同类型事件。
1.2 DOM 2 级事件
DOM 2 级事件在 DOM 0 级事件的基础上弥补了一个处理程序无法同时绑定多个处理函数的缺点,允许给一个处理程序添加多个处理函数。代码如下:
<button id="btn" type="button"></button>
<script>
var btn = document.getElementById('btn');
function showFn() {
alert('Hello World');
}
btn.addEventListener('click', showFn, false);
// btn.removeEventListener('click', showFn, false); 解绑事件
</script>
DOM 2 级事件定义了 addEventListener 和 removeEventListener 两个方法,分别用来绑定和解绑事件。均有三个相同的参数,具体如下: el.addEventListener(eventName, callback, useCapture)
eventName: 事件名称(名字不带 on) callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event useCapture: 默认缺省或 false,代表事件在冒泡阶段执行
需要注意的是 IE8 以下版本不支持 addEventlistener 和 removeEventListerner ,需要使用 attachEvent 和 detachEvent 实现:
btn.attachEvent('onclick', showFn); // 绑定事件
btn.detachEvent('onclick', showFn); // 解绑事件
小结
el.addEventListener(eventName, callback, useCapture)
DOM 2 级事件处理程序能够为同一元素绑定多个同类型事件
1.3 DOM 3 级事件 在 DOM 2 级事件的基础上添加了更多的事件类型。
- UI 事件,当用户与页面上的元素交互时触发,如:load、scroll
- 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
- 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup
- 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
- 文本事件,当在文档中输入文本时触发,如:textInput
- 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
- 合成事件,当为 IME(输入法编辑器)输入字符时触发,如:compositionstart
- 变动事件,当底层 DOM 结构发生变化时触发,如:DOMsubtreeModified 同时 DOM 3 级事件也允许开发者自定义事件。
- DOM 事件模型 浏览器在发展的过程中出现了两种不同的规范
IE 浏览器使用的是事件冒泡,在目标节点从小至大传播。 网景浏览器使用的是事件捕获,在目标节点从大至小传播。 为了规范开发标准,W3C 制定的 Web 标准中,同时采用了两种方案,事件捕获和事件冒泡都可以,但默认使用事件冒泡。
DOM 事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段:
捕获阶段:事件从 window 对象自上而下向目标节点传播的阶段; 目标阶段:真正的目标节点正在处理事件的阶段; 冒泡阶段:事件从目标节点自下而上向 window 对象传播的阶段。
- 事件委托(事件代理) 原理:由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。 把一个元素响应事件的函数委托给该元素的外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素执行函数。
优点: 减少内存消耗
假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我们只需要给父容器 ul 绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的 click 行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。
动态绑定事件
在很多时候,需要通过 AJAX 或者用户操作动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件; 使用事件委托将事件绑定在父层,与目标元素的增减没有关系,执行到目标元素是在真正响应执行事件函数的过程中去匹配的,可以减少很多重复工作的。