使用 e.stopPropagation() 防止事件冒泡的优点和缺点

2024-02-28

很多人都解释过e.stopPropagation()防止事件冒泡。然而,我很难找到why人们首先想要或想要阻止事件冒泡。

在我的网站上,我有许多元素,其名称如下:

$(document.body).on('click', ".clickable", function(e){ 
   //e.stopPropagation();
  //do something, for example show a pop-up or click a link   
});

<body>
  <p>outside stuff</p>
  <button type="button" class='clickable'>
    <img src='/icon.jpg'> Do Something

  </button>
</body>

我想添加e.stopPropagation()因为我想将事件处理程序更改为'touch' from 'click' using 这个很棒的触摸库,Hammer.js。 http://eightmedia.github.io/hammer.js/。这将允许在桌面上正常单击并在移动设备上正常发生触摸事件。

这样做的问题(如果我错了,请纠正我)是在触摸设备上滚动会减慢直至停止。

这是哪里吗e.stopPropgation()有用吗?这样每当有人触摸屏幕时document.body- 事件冒泡是NOT每次都发生?


有多种方法可以处理 javascript/jQuery 中的事件。其中两个是:

  1. 您可以在对象上使用直接事件处理程序。
  2. 您可以使用委托事件处理来处理父级上的传播事件。

如果您在对象上使用直接事件处理程序并且页面中没有配置委托事件处理程序,则没有理由e.stopPropagation().

但是,如果您有使用传播的委派事件处理程序,您有时需要确保更高级别的委派事件处理程序不会在当前事件上触发。

在你的具体例子中:

$(document.body).on('click', "a.ajaxLink", function(e){ 

这是一个委托事件处理程序。它正在寻找传播到的任何点击事件document.body对象,但起源于a.ajaxLink目的。在这里,优势不大e.stopPropagation()因为事件几乎已经完全传播了(它也会上升到document,但除非你还有一个处理程序click on the document对象,那么就没有理由e.stopPropagation()在这个处理程序中。

当您同时拥有顶级委托事件处理程序(如示例中的事件处理程序)和较低级别事件处理程序(直接在对象上或使用委托事件处理,但在一个水平低于document.body目的。在这种情况下,如果您只想让较低级别的事件处理程序获取事件,那么您可以调用e.stopPropagation()在它的处理程序中,以便document.body处理程序从未见过该事件。

$("a.ajaxLink").click(function(e) {
    if (some condition) {
        // do something specific to this condition
        code here
        // stop propagation so the default behavior for click in document.body does not fire
        e.stopPropagation();
    }
})

注意:使用return false来自 jQuery 事件处理程序同时触发e.stopPropagation() and e.preventDefault()。但是,如果您处于委托事件处理程序中,e.preventDefault()不执行任何操作,因为当目标对象第一次看到该事件时,默认行为(如果有)已经触发。默认行为发生在事件传播之前,因此e.preventDefault()仅适用于直接作用于目标对象的事件处理程序。


没有明显的性能下降,因为您允许事件冒泡,因为这些是用户级事件,并且它们发生的速度不够快,所以没有影响,当所有介入对象上没有处理程序时,冒泡特别慢。系统已经对某些事件进行了特殊处理,例如mousemove这可以迅速解决该问题。如果您有一个包含数百或数千个事件处理程序的大型项目,则在某些情况下使用委托事件处理会更有效,而在实际目标对象上直接使用事件处理程序在某些情况下会更有效。但是,除了在巨大的场景中,性能差异可能并不明显。

这是一个冒泡/委托更有效的示例。您有一个包含数千行的巨大表格,每行都有两个按钮(例如添加/删除)。通过委派事件处理,您可以在附加到表对象(按钮的公共父级)的两个简单事件处理程序中处理所有按钮。这将比直接在每个按钮上安装数千个事件处理程序更快地安装事件处理程序。这些委托的事件处理程序还将自动处理表中新创建的行/对象。这是事件冒泡/委托事件处理程序的理想场景。请注意,在这种情况下,没有理由停止传播/冒泡。

下面是委托事件处理程序效率非常低的示例。假设您有一个大小合适的网页,其中包含数百个对象和事件处理程序。您可以使每个事件处理程序都成为附加到document目的。但是,这就是发生的事情。发生咔嗒声。实际对象上没有事件处理程序,因此它会冒泡。最终,它到达文档对象。文档对象有数百个事件处理程序。事件处理引擎(本例中为 jQuery)必须查看每一个事件处理程序,并将每个事件处理程序的委托事件处理程序中的选择器与原始事件目标进行比较,看看它们是否匹配。其中一些比较速度并不快,因为它们可能是成熟的 CSS 选择器。它必须为数百个委托事件执行此操作。这对性能不利。这就是为什么.live()jQuery 中的 已被弃用,因为它是这样工作的。相反,委托事件处理程序应尽可能靠近目标对象放置(在特定情况下,最接近的父对象)。而且,当不需要委托事件处理程序时,应将处理程序放在实际的目标对象上,因为这在运行时是最有效的。


回到你原来的问题。一般来说,您不希望关闭冒泡。正如我之前在回答中所描述的,在某些特定情况下,树上更远的事件处理程序想要处理该事件并阻止 DOM 树中更高层的任何委托事件处理程序处理此事件。那是时候了e.stopPropatation().


以下是其他几篇相关帖子,其中包含有关此主题的有用信息(因为之前已经广泛讨论过):

为什么不将 Javascript 事件委托发挥到极致呢? https://stackoverflow.com/questions/9711118/why-not-take-javascript-event-delegation-to-the-extreme/9711252#9711252

所有 jquery 事件都应该绑定到 $(document) 吗? https://stackoverflow.com/questions/12824549/should-all-jquery-events-be-bound-to-document/12824698#12824698

jQuery.on() 是否适用于创建事件处理程序后添加的元素? https://stackoverflow.com/questions/9814298/does-jquery-on-work-for-elements-that-are-added-after-the-event-handler-is-cre/9814409#9814409

jQuery on() 和 stopPropagation() https://stackoverflow.com/questions/11910735/jquery-on-and-stoppropagation/11910746#11910746

避免将大量 DOM 对象绑定到单击事件相关的内存或性能问题的最佳实践 https://stackoverflow.com/questions/15594663/best-practice-to-avoid-memory-or-performance-issues-related-to-binding-a-large-n/15595375#15595375

jQuery .live() 与 .on() 方法在加载动态 html 后添加点击事件 https://stackoverflow.com/questions/8752321/jquery-live-vs-on-method-for-adding-a-click-event-after-loading-dynamic-ht/8752376#8752376

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 e.stopPropagation() 防止事件冒泡的优点和缺点 的相关文章

随机推荐

  • 将全天活动添加到 Google 日历的链接

    所以我看了看添加到 Google 日历的链接 https stackoverflow com questions 10488831 link to add to google calendar 但我想对全天活动做同样的事情 我试过做date
  • ExecutorService,如何知道所有线程何时完成而不阻塞主线程?

    我有一个多线程实现 我创建一个 ExecutorService 并提交要执行的任务 我想知道所有线程何时提交完成而不阻塞主线程和 UI 我试过了ExecutorService awaitTermination 但它会阻塞主线程和 UI 我已
  • 双线性插值

    我得到了通过双线性插值缩放图像的代码 我知道这是可行的 但我无法弄清楚如果近似像素值是边缘 边缘我的意思是它在最后一行或最后一列 像素中的一件事会怎样输入图像然后我可以 gt 坐标 x 1 y 1 的像素 这应该会导致数组索引超出范围错误
  • 如何将数组缓冲区数据与 string/json 一起发送到 NodeJS 服务器

    我需要在一个请求中将客户端页面的图像数据 作为数组缓冲区读取 以及页面生成的附加字符串 json 信息发送到 NodeJS 服务器 我需要在一个请求中处理这两个部分 因为服务器的进一步图像处理取决于发送的字符串 json 有哪些方法可以由客
  • 使用 py.test 在 Python 中测试正则表达式

    正则表达式对我来说仍然是一门黑暗艺术 但我认为这是需要练习的事情之一 因此 我更关心能够生成 py test 函数来显示我的正则表达式失败的地方 我当前的代码是这样的 my regex re compile
  • 与集合和泛型相关的 Java 10 迁移问题

    继续我之前在链接中的查询 Java 10 上的 Swing 问题 https stackoverflow com questions 51555030 swing issue on java 10 noredirect 1 comment9
  • 性能测试 OpenLayers 与 Leaflet

    我想比较 OpenLayers 和 Leaflet 之间的性能 我想测试诸如渲染矢量文件 底图 显示大量标记等最快的东西 我可以自己设置这个例子 但我不知道如何实际测量它们之间的速度差异 在哪里可以看到执行将矢量数据加载到地图等任务实际需要
  • 单独项目中的 nHibernate 域模型和映射文件

    有没有办法将域对象和映射文件分离到两个单独的项目中 我想创建一个名为 MyCompany MyProduct Core 的项目 其中包含我的域模型 以及另一个名为 MyCompany MYProduct Data Oracle 的项目 其中
  • GKE 入口 https 重定向 - FrontendConfig 无法识别

    我有一个同时包含 Http 和 Https 的 GKE 入口 我想将流量从端口 80 重定向到端口 443 我找到了这个 https github com kubernetes ingress gce issues 1075 https g
  • 无法加载配置“airbnb”以扩展 - gitlab ci

    我尝试以各种方式进行和重做 Airbnb eslint 安装 但我总是在 GitLab ci 中遇到此构建错误 它适用于我当地的环境 我使用 create react app 创建了项目 单独安装了依赖项 以免覆盖 eslint 版本 但我
  • 如何将 stderr out 和 stdout out 重新定义为单独的日志?

    如何使用日志记录模块重新定义 stderr out 和 stdout out 以单独记录文件 例如 stderr log 和 stdout log 文件 您可以简单地替换sys stdout and sys stderr使用自定义的类似文件
  • Firestore 强制用户编写 id 等于其自己的 uid 的文档的规则

    我想保证用户只能添加与其 auth uid 具有相同 id 的文档 例如 ID 为 1X0T6xC6hhRN5H02zLCN6SQtwby2 的用户只能创建 更新文档 salesmen 1X0T6xC6hhRN5H02zLCN6SQtwby
  • 如何为 Kubernetes 集群确定合适的 pod CIDR 值?

    我正在启动一个 kubernetes 集群 kubeadm init pod network cidr 192 168 1 0 16 apiserver advertise address 192 168 0 33 我对网络概念或 CIDR
  • Nuget.exe 安装 — Microsoft.CSharp 已经具有 System.Dynamic.Runtime 的依赖项

    我们通过 CI 构建中的 PowerShell 预构建脚本安装一些包 最近 我们收到了部分成功的电子邮件通知 其中提供了以下信息 Microsoft CSharp 已经具有为 System Dynamic Runtime 定义的依赖项 以下
  • YAML Jackson - 数组的锚键

    我正在尝试将 YAML 文件解析为对象 尽管 Online YAML 解析器告诉我它可以按照我想要的方式进行解析 但 Jackson YAML 解析器拒绝给我我想要的东西 这是 YAML 文件 nom service1 etats e1s1
  • 为什么 MultiMap 中不保留插入顺序?

    public class MultiMap Test public static void main String args Multimap
  • Spring MVC 预填充复选框

    首先是一些背景信息 获得了相当标准的用户角色关系 其中用户可以拥有多个角色 我将角色定义为用户类中的一组 现在我知道 html 表单将所有值都作为字符串 并且尝试获取值 因为我的自定义 Role 对象不起作用 我实现了一个 initbind
  • C2440 static_cast 无法从基类转换为派生类

    我试图理解为什么使用指针从基类到派生类的转换编译得很好 但使用非指针对象进行转换会产生错误 C2440 下面我有一个基类ThreadedMessage这是由类继承的GPSMessage struct ThreadedMessage Thre
  • 如何阻止 [Required] 注释在被覆盖的字段上被继承?

    我有一个电话号码通知模型 用户通过与帐户关联的电话号码收到紧急情况通知 并且可以设置呼叫的顺序 大多数时候 模型的电话号码部分是必需的 但在创建新用户时有一种特殊情况 我们不想强制它 我创建了一个非常简单的子对象 UserCreationP
  • 使用 e.stopPropagation() 防止事件冒泡的优点和缺点

    很多人都解释过e stopPropagation 防止事件冒泡 然而 我很难找到why人们首先想要或想要阻止事件冒泡 在我的网站上 我有许多元素 其名称如下 document body on click clickable function