使用 event.stopPropagation() 阻止事件传播

目录

  • 背景
  • DOM 事件传播模型
  • 分析一下我上面的例子
  • 使用 event.stopPropagation() 阻止事件传播
  • 参考连接

背景

我最近参与的项目涉及开发一个公司内部使用的组件库,我在开发一个搜索框组件时遇到了一个麻烦的问题。简单来说是:

使用 event.stopPropagation() 阻止事件传播_第1张图片

  • 点击外层容器会聚焦在输入框上。这是别人写的底层组件上的逻辑,不方便改;
  • 我希望点击容器中的 icon 时(是个返回箭头),输入框会失焦。

写好 event handler 之后试了一下发现,每次点击容器内部的 icon,都无法实现失焦的效果。显然,内部 icon 的 handler 触发失焦之后,event 又继续传播到了外层容器,并触发相应 handler,结果又聚焦在输入框上了。

当时比较着急,就没处理这个细节直接提交了。昨天回过头来做这个,同事一下点醒了我:阻止事件传播就可以了!

DOM 事件传播模型

之前了解过 DOM 事件传播模型,但从来没有真正遇到过相关的问题,这次终于碰上了一回!

简单来说,当你点击一个层层嵌套的 DOM 元素(目标元素)时,会发生下面这些事情:

  • Capture 阶段:浏览器首先会检查最外层元素是否注册了 capture 模式的点击事件 listener,如果有则执行相应 handler;然后检查更靠近目标元素的下一层元素,如此反复,直到处理完目标元素的 capture 模式的点击事件 listener;
  • Bubble 阶段:检查目标元素是否注册了 bubble 模式的点击事件 listener,如果有则执行相应 handler;然后检查其上一层的元素,不断重复此过程,直到没有更上一层的元素;

现代浏览器都同时支持capturebubble 模式,所以这两个阶段都会有。当你注册一个 listener 时:

target.addEventListener(type, listener, useCapture);

第三个参数 useCapture 就用来设置模式,默认为 false 即使用 bubble 模式,如果指定为 true 则使用 useCapture 模式。

分析一下我上面的例子

具体到我上面的例子,只考虑容器和 icon 这两个元素:

  • 点击内部 icon,首先进入 capture 阶段。我没有真正写过 addEventListeneraddEventListener 是前端框架替我加上去的,使用的也都是默认的 bubble 模式,所以这个阶段不会触发任何 handler;
  • 然后进入 bubble 阶段,触发 icon 的点击事件 handler,输入框失焦;
  • bubble 阶段,事件传播到外层容器,触发相应 handler,输入框重新聚焦;

使用 event.stopPropagation() 阻止事件传播

解决我上面遇到的问题也很简单,只需要在内部 icon 的点击事件 handler 上加一句:

event.stopPropagation() 

就可以了。这样一来,事件就不会继续传播了,无论目前是处在 capture 还是 bubble 阶段。

也就是说,在内部 icon 阻止了事件继续传播到外层容器上。

参考连接

Event.stopPropagation()
What’s the difference between event.stopPropagation and event.preventDefault?

你可能感兴趣的:(JavaScript,前端,javascript,html)