细数JS之事件模型(未完)

undefined

js与html的交互是通过事件实现的。交互动作都需要事件驱动,那么今天,一起来细数一下事件模型吧~~

事件与监听

这块应该是很好理解的内容。在事件发生之前,进行订阅监听(监听下课铃响了没)。某个元素发生了什么事情,这就是一个事件。因为进行了监听,所以可以进行相应操作(下课)。假设一下,如果你没有听到下课铃,就没有办法下课(监听事件没被触发)。这里监听就是常说的侦听器。

事件流

好了,然后这里的描述可能需要你稍微动一动自己的形象思维。事件流————事件触发的顺序。因为一个标准的html文件,它是这样包含与被包含关系。也就是<html>标签下包含着<body></body>标签。这就有点像在一张纸上,画上很多个同心圆,然后你手指指在圆心上。这时候,你到底指的是哪个圆呢???

于是就出现了两种事件流————事件冒泡、事件捕获

事件冒泡

IE提出的事件流叫事件冒泡,即事件开始时由最具体的元素(具体的按钮)接受,之后逐级往上传播到较为不具体(例如页面元素<body>)的节点。这个也就是我们常用的事件流,应该能很容易理解。

事件捕获

Netscape团队提出的事件捕获的概念也并不复杂,甚至说只要将事件冒泡的概念调转过来就行。先触发不具体,到具体

这里推荐使用事件冒泡,特殊情况下再使用事件捕获。

DOM事件流

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和
事件冒泡阶段。
,首先发生的是事件捕获阶段,为截获事件提供了机会。然后是实际的目标接受到事件。最后是事件冒泡阶段。(详细见图,如果图不在了,自行百度)

在DOM事件流中,实际目标(text)在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从window => document => body => div后就停止了。下一个阶段是“处于目标”阶段,于是事件在(text)上发生,并在事件处理中被看成冒泡阶段的一部分。然后,冒泡阶段发生,事件被传回window。但是重点来了,虽然规范这么说,但是浏览器厂商就是任性不听话,它们都会在捕获阶段触发实际目标事件。于是就有两个机会在目标对象上操作事件。

事件处理程序

HTML事件处理程序

也就是直接在html标签上绑定点击事件。但是由于这里有些缺点。

  • 事件在没有执行函数没被解析之前触发,导致错误。需要try{}catch{}急性捕获。

    1
    <input type="button" value="aa" onclick="try{showMessage();}catch(err){}"
  • 需要转义一些字符

  • HTML和js代码耦合

所以一般不推荐,只有在腾讯统计代码的部分,我才使用过这个处理程序,其他情况几乎不存在。

DOM0级事件处理程序

也就是长这样的

1
2
var btn = document.getElementById('myBtn');
btn.onclick = function(){}

以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
而想要删除绑定时间也很简单。

1
btn.onclick = null; // 删除事件处理程序

于是从这里你就能轻松发现。虽然它添加事件和删除事件都超级无敌方便。但是有一个致命的缺点————不能同时对同一个事件绑定两个监听函数。(也就是小明它监听了闹钟有没响这个事件后,小红就不能介入监听了)这显然不适应很多情况。

DOM2级时间处理程序

两个方法:addEventListener()、removeEventListener()添加和删除事件处理程序。所有的DOM节点都包含这两个方法,并且它们接受3个参数:事件名、事件处理程序,布尔值。这个布尔值的参数如果是true,那么将在捕获阶段调用,如果是false,那么将在冒泡阶段调用事件处理程序。

通过addEventListener()添加的事件处理程序,只能用removeEventListener()来移除;移除时需要传入的参数和添加时传入的参数一致。这就意味着匿名函数无法移除(即使是相同构成的匿名函数在编译器也会分配成两块不相同的内存。)

另外,这两个方法支持添加多个事件监听,触发顺序和绑定顺序一致。

大多数情况下,都是将时间处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。

IE事件处理程序

主要还是为了兼容IE9以下的浏览器。attachEvent()detachEvent()

  • 注意的是,没有第三个参数。因为IE只有事件冒泡
  • 参数传入的是onclick, 而不是click.
  • 同样不能取消绑定匿名函数

…纳闷,内容太多。先当一个坑吧

事件对象

事件类型

内存与性能

模拟事件