Skip to content

Latest commit

 

History

History
115 lines (93 loc) · 6.58 KB

6.7.3.md

File metadata and controls

115 lines (93 loc) · 6.58 KB

6.7.3 取消事件处理

  使用事件对象的stopPropagation/stopImmediatePropagation/preventDefault方法,可以中途取消事件处理。在本项中,将介绍如何正确使用这些方法。

【346页】

●事件的传播
  在介绍取消事件处理之前,再稍微看一点关于触发事件到调用事件处理为止的过程。目前为止,只介绍了「如果发生了事件就调用事件监听器」,但其实事件在到达特定的元素之前,还经历了如下的阶段。 image

①捕获阶段从window对象开始向下传播事件
②目标阶段找到触发事件的对象 发生事件
③冒泡阶段将底层元素中发生的事件向上传播

●事件的传播

  首先,在捕获阶段,从最上层的window对象开始,沿着文档树向下传播事件。然后,在目标阶段找到触发事件的元素。
  冒泡阶段,是从触发事件的元素开始朝着根元素传播事件的阶段。最终,在到达了最上层的window对象时结束事件的传播。事件传播到父元素的样子和气泡(bubble)上浮的样子很像,所以称为冒泡。
  这里需要理解的是「事件监听器不仅仅只在触发事件的元素中执行」这一点。在捕获/冒泡阶段的过程中,如果有对应的事件监听器,这些也会依次执行。
  我们来看下具体的例子吧。

●清单6-45 propagation.html(上)/propagation.js(下) image image

outer元素
inner元素
元素的click事件监听器
'触发了#inner监听器。'
'触发了#inner监听器2。'
元素的click事件监听器
'触发了#outer监听器。'

【347页】

  对有父子关系的<div><a>元素分别设定click事件监听器。这时,点击链接,按照下面的顺序执行处理。

  1. 显示对话框(触发了#inner监听器)
  2. 显示对话框(触发了#inner监听器2)
  3. 显示对话框(触发了#outer监听器)
  4. 按照链接跳转页面

  这是因为将触发事件的元素作为基点,向上依次执行事件监听器。也可以说是「在冒泡阶段处理了事件」。如果对同一个元素设定了多个事件监听器,则按照书写的顺序执行。
  这个顺序,也可以使用addEventListener方法的第3个参数来改变。试着将示例的粗体字部分改为true。这次,得到了如下的结果。

  1. 显示对话框(触发了#outer监听器)
  2. 显示对话框(触发了#inner监听器)
  3. 显示对话框(触发了#inner监听器2)
  4. 按照链接跳转页面

  从上层节点开始朝着触发事件的元素依次执行事件监听器。在捕获阶段处理了事件。

■取消事件的传播
  有时,我们需要取消这些事件的传播、或者是事件处理时浏览器本身的动作。例如,在之前的例子中,「只执行<a id="inner">元素中的事件监听器,忽略上层的事件监听器」等。

【348页】

  这时,需要使用stopPropagation方法。
  例如,下面的代码是在之前的清单6-45中,对<a id="inner">元素添加stopPropagation方法。

●清单6-46 event_cancel.js image

元素的click时间监听器
'触发了#inner监听器。'
'触发了#inner监听器2。'
'触发了#outer监听器。'

  运行示例,点击链接,可以得到如下的结果。

  1. 显示对话框(触发了#inner监听器)
  2. 显示对话框(触发了#inner监听器2)
  3. 按照链接跳转页面

  这是因为取消了向父节点的冒泡。当然,在捕获阶段执行事件监听器时,在上层节点调用stopPropagation方法也可以同样取消事件的传播。

■立刻取消事件的传播
  stopPropagation方法是取消向上/向下传播事件,相对的,如果要立刻取消传播(=在同一个元素中注册的监听器也不执行),需要使用stopImmediatePropagation方法。
  将清单6-46中的①如下改写,并同样地执行。

●清单6-47 event_cancel.js

e.stopImmediatePropagation();
【349页】

  下面,是运行结果。

  1. 显示对话框(触发了#inner监听器)
  2. 按照链接跳转页面

  我们可以看到,在<div id="inner">元素中注册的第2个click事件监听器没有执行。

■取消事件的默认动作
  事件的默认动作是指例如点击锚标签是「页面跳转」,在输入框中按下键是「显示输入的字符」等浏览器默认的动作。使用事件对象的preventDefault方法可以取消这些动作。
  同样的,像下面这样改写清单6-46的①并执行。

●清单6-48 event_cancel.js

e.preventDefault();

  下面,是运行结果。

  1. 显示对话框(触发了#inner监听器)
  2. 显示对话框(触发了#inner监听器2)
  3. 显示对话框(触发了#outer监听器)

  我们可以看到所有的传播都结束了之后,没有跳转页面。

Note 也有不能取消的事件
  也有使用preventDefault方法不能取消的事件。事件是否可以取消,同样可以使用事件对象的cancelable属性来判断。如果事件可以取消,cancelable属性返回true。

Note 在事件处理器中取消
  在事件处理器中,将false作为返回值返回,可以取消事件默认的动作。例如,下面的例子是取消contextmenu事件,使右键菜单不显示。想要实现应用自己特有的右键菜单时,需要像这样使浏览器默认的菜单无效。

<div oncontextmenu="return false;">...</div>
【350页】

  那么,介绍了所有的取消类的方法了,我们将其使用表格罗列出来,好好整理比较一下。

方法 传播 其他的监听器 默认的动作
stopPropagation 停止 -
stopImmediatePropagation 停止 停止 -
preventDefault - - 停止
●取消事件

  也就是说要取消之后的事件传播、默认的动作,调用stopImmediatePropagation/preventDefault方法就可以了。