chuanFE

事件冒泡和事件捕获

一 事件阶段

一般的,事件分为三个阶段:捕获阶段、目标阶段和冒泡阶段。

1 捕获阶段:

事件的第一个阶段是捕获阶段。事件从最不精确的对象(文档根节点)开始触发,然后到触发最精确的对象(目标对象节点)结束。途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达事件的目标节点。当你使用事件捕获时,父级元素事件先触发,子级元素后触发。
作用:捕获阶段的主要任务是建立传播路径,在冒泡阶段,事件会通过这个路径回溯到文档跟节点。

2 目标阶段:

当事件到达目标节点的,事件就进入了目标阶段。事件在目标节点上被触发,然后会逆向回流,直到传播至最外层的文档节点。

3 冒泡阶段:

事件按照从最精确的对象(目标对象节点)开始触发,一直到最不精确的事件目标(文档根节点)的顺序触发结束。事件在目标元素上触发后,并不在这个元素上终止。它会随着DOM树一层层向上冒泡,回溯到根节点。当你使用事件冒泡时,子级元素事件先触发,父级元素后触发。
作用:冒泡过程非常有用。它将我们从对特定元素的事件监听中释放出来,如果没有事件冒泡,我们需要监听很多不同的元素来确保捕获到想要的事件。

二 冒泡阶段调用事件处理函数

三 捕获阶段调用事件处理函数

四 事件代理

在传统的事件处理中,你按照需要为每一个元素添加或者是删除事件处理器。然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越大。JavaScript事件代理可以把事件处理器添加到一个父元素上,这样就避免了把事件处理器添加到多个子元素上。

1 如何运作

事件代理用到了两个JavaSciprt事件特性:事件冒泡以及目标元素。当一个元素上的事件被触发的时候,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡;使用事件代理,我们可以把事件处理器添加到一个元素上,等待一个事件从它的子级元素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。

2 带来的好处

比如说在一个10列、100行的HTML表格里,让其每一个单元格在被点击的时候变成可编辑状态。如果把事件处理器加到这1000个单元格会产生一个很大的性能问题,并且有可能导致内存泄露甚至是浏览器的崩溃。相反地,使用事件代理,你只需要把一个事件处理器添加到table元素上就可以了,这个函数可以把点击事件给截下来,并且判断出是哪个单元格被点击了。

五 阻止事件冒泡(stopPropagation)

1 什么时候要阻止事件冒泡

当父类也有同样类型的方法,但在调用子类方法的时候不想触发父类方法的时候要阻止冒泡。
例如:document上有A事件,div有B事件,div里面的span有C事件,如果不给span和div加阻止事件冒泡的话,点击span时就会触发到div的B事件、document的A事件,当点击span时不想触发div和document的事件就要加上阻止事件冒泡,div也是一样的道理。如果不加阻止事件冒泡,便会由于事件冒泡,该DOM目标节点的所有父节点事件也会触发,执行了回调函数,这样就违背了最初的本意了。

2 如何阻止事件冒泡

阻止事件冒泡有3种方法

(1) event.stopPropagation();

事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)

(2) return false;

事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)

(3) event.preventDefault();

如果把它放在头部A标签的click事件中,点击“点击我”。
会发现它依次弹出:我是最里层—->我是中间层—->我是最外层,但最后却没有跳转到百度
它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转)

3 无法在捕获阶段阻止事件冒泡

这里需要注意的是,我们无法在事件捕获阶段阻止事件冒泡。例如,我们在代码里加上true,如图所示,第一个li会触发事件。因为捕获是从根节点向目标节点触发,而冒泡是从目标节点向根节点触发。

我知道是不会有人点的,但万一有人想不开呢?