JavaScript | DOM事件等级

DOM事件级别是前端中比较常见的知识点,简单写一篇博客对这个知识点做个汇总。

为什么引入DOM级别

在 IE4 和 Netscape Navigator 4 支持不同形式的动态 HTML(DHTML)的情况下,开发者首先可以做到不刷新页面而修改页面外观和内容。这代表了 Web 技术的一个巨大进步,但也暴露了很大的问题。由于网景和微软采用不同思路开发 DHTML,开发者写一个 HTML 页面就可以在任何浏览器中运行的好日子就此终结。 为了保持 Web 跨平台的本性,必须要做点什么。人们担心如果无法控制网景和微软各行其是,那么 Web 就会发生分裂,导致人们面向浏览器开发网页。就在这时,万维网联盟(W3C,World Wide WebConsortium)开始了制定 DOM 标准的进程。

——出自《JavaScript高级程序设计》

DOM等级

常见的DOM事件等级有三种,分别为DOM Level 1、DOM Level 2以及DOM Level 3,对于不同等级的DOM,对应的DOM事件处理方式也是不同的。

DOM Level 0

不是说DOM事件等级有三种吗?可能有些人看晚上大部分文章都有写DOM Level 0,但是实际上并没有一个标准叫DOM Level 0,详细可以参考下面的引用:

在阅读关于 DOM 的资料时,你可能会看到 DOM Level 0 的说法。注意,并没有一个标准叫“DOM Level 0”,这只是 DOM 历史中的一个参照点。DOM Level 0 可以看作 IE4和 Netscape Navigator 4 中最初支持的 DHTML。

——出自《JavaScript高级程序设计》

所以上文的引用所提到的DOM Level 0指的是在DHTML中的这种写法:

1
2
3
4
5
6
<div onclick="test()"></div>
<script>
  test() {
    console.log('test');
  }
</script>

常用的事件有下面这些:

  • onload
  • onunload
  • onchange
  • onsubmit
  • onreset
  • onselect
  • onblur
  • onfocus
  • onkeydown
  • onkeyup
  • onkeydown vs onkeyup
  • onkeypress
  • onmouseover 和 onmouseout
  • onclick
  • ondblclick
  • onmousedown 和 onmouseup
  • onmousemove

不过这种写法有个致命缺陷,就是不能给一个元素添加多个点击事件,比如下面一个例子:

需求:给div添加两个点击事件

如果使用DHTML中的写法

HTML&CSS:

1
2
3
4
5
6
7
8
<style>
  div {
    width: 100px;
    height: 100px;
    background-color: aquamarine;
  }
</style>
<div></div>

JS:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let div = document.querySelector('div');
function test1() {
  console.log('test1');
}

function test2() {
  console.log('test2');
}

div.onclick = test1; // 后面不要加括号,会变成调用函数
div.onclick = test2;

现在点击页面上的div元素,发现只会输出test2,后面的事件会覆盖前面的事件,说明使用DHTML中的这种写法不能满足这个案例的需求,所以才会有了后面的DOM Level1,DOM Level2的标准。

如何解除事件绑定

对于这种写法如果要解除事件绑定,只需要把null赋值给事件属性即可,对于所以对于上面的案例可以使用以下的写法即可解除引用:

div.onclick = null;

补充

对于这种写法的事件都是冒泡进行的,无法使用事件捕获。

DOM Level 1

1998 年 10 月,DOM Level 1 成为 W3C 的推荐标准。这个规范由两个模块组成:DOM Core 和 DOM HTML。前者提供了一种映射 XML 文档,从而方便访问和操作文档任意部分的方式;后者扩展了前者,并增加了特定于 HTML 的对象和方法(比如:JavaScript中的Document对象)。

——出自《JavaScript高级程序设计》

大家熟知的Nodedocument, document.createElement都是在DOM1级别定义的,所以总结一下DOM Level 1的目标是映射文档结构没有定义事件相关的内容,所以没有DOM Level 1对应的事件,这里就不做过多的讨论了。

DOM Level 2

DOM Level 1 的目标是映射文档结构,而 DOM Level 2 的目标则宽泛得多。这个对最初 DOM 的扩展增加了对(DHTML 早就支持的)鼠标和用户界面事件、范围、遍历(迭代 DOM 节点的方法)的支持,而且通过对象接口支持了层叠样式表(CSS)。另外,DOM Level 1 中的 DOM Core 也被扩展以包含对 XML 命名空间的支持。

——出自《JavaScript高级程序设计》

DOM Level 2引入了大量事件方法的支持,同时解决了DHTML的写法(DOM Level 0)中无法绑定多个处理函数的缺点,允许给一个元素添加多个处理函数

DOM Level 2定义了addEventListener方法,用于给对象绑定事件

语法:

EventTarget.addEventListener(EventType, callback, useCapture)

参数:

  1. EventType:事件类型
  2. callback:事件处理的对应回调函数
  3. useCapture:是否使用事件捕获,默认为false,代表不使用

可以看到在DOM Level 2中可以使用事件捕获了,这也是相比DHTML的写法(DOM Level 0)中改动比较多的一个地方了。

如何解除事件绑定

在DOM Level 2定义了removeEventListener方法,用于解除绑定的事件对象。

语法:

EventTarget.removeEventListener(EventType, listener, useCapture)

参数:

  1. type:要移除的事件类型
  2. listener:要移除的函数
  3. useCapture:指定需要移除的函数是否为捕获监听器

所以现在就可以针对DHTML的写法(DOM Level 0)的案例做一个修改,以便满足需求了,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let div = document.querySelector('div');
// 两次都会一次触发
div.addEventListener('click', add);
div.addEventListener('click', function(){
  alert('click2');
});

// 解除绑定
function add() {
  alert('click1');
  // 点击一次后不再触发
  div.removeEventListener('click', add);
}

❕注意:如果给addEventListener绑定的是一个匿名函数,会导致此事件无法解绑定

DOM Level 3

DOM Level 3 进一步扩展了 DOM,增加了以统一的方式加载和保存文档的方法(包含在一个叫 DOM Load and Save 的新模块中),还有验证文档的方法(DOM Validation)。在 Level 3 中,DOM Core 经过扩展支持了所有 XML 1.0 的特性,包括 XML Infoset、XPath 和 XML Base。

——出自《JavaScript高级程序设计》

同时DOM Level 3中在DOM Level 2的基础上增加了更多事件的支持,详细的信息参考下面的的列表

事件 描述
UI事件 当用户与页面上的元素交互时触发,如:load、scroll
焦点事件 当元素获得或失去焦点时触发,如:blur、focus
鼠标事件 当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
滚轮事件 当使用鼠标滚轮或类似设备时触发,如:mousewheel
文本事件 当在文档中输入文本时触发,如:textInput
键盘事件 当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
合成事件 当为IME(输入法编辑器)输入字符时触发,如:compositionstart
变动事件 当底层DOM结构发生变化时触发,如:DOMsubtreeModified

同时DOM3级事件也允许使用者自定义一些事件。

DOM Level 4

目前,W3C 不再按照 Level 来维护 DOM 了,而是作为 DOM Living Standard 来维护,其快照称为DOM4。DOM4 新增的内容包括替代 Mutation Events 的 Mutation Observers。

——出自《JavaScript高级程序设计》

详细请看 W3C DOM4

总结

  • DOM Level 0
    • 无法绑定多个事件
    • 解除事件绑定将对象赋值为null即可
    • 事件都是冒泡进行,无法改为事件捕获
  • DOM Level 1
    • Nodedocument, document.createElement都是在此时定义的
    • 添加了针对HTML的对象和方法,如Document对象
  • DOM Level 2
    • 定义了addEventListenerremoveEventListener两个方法,用于绑定事件与解除绑定(必须使用此方法解除绑定)
    • 使用addEventListener可以给一个对象同时绑定多个事件
    • 可以通过addEventListenerremoveEventListener第三个参数去确定是在冒泡或者捕获阶段执行
    • 匿名函数无法解除绑定
  • DOM Level 3
    • 添加了更多事件的支持

参考文献