草庐IT

javascript - 多个 addEventListener 如何在 JavaScript 中工作?

coder 2024-05-10 原文

一个文档中有两个脚本:

// my_script.js goes first
document.onclick = function() {
    alert("document clicked");
};

// other_script.js comes after
// this overrides the onclick of my script,
// and alert will NOT be fired
document.onclick = function() {
    return false;
};

为了确保我的 click 事件不会被其他脚本覆盖,我切换到 addEventListener

// my_script.js goes first
document.addEventListener("click", function() {
    alert("document clicked");
}, false);

// other_script.js comes after
document.addEventListener("click", function() {
    return false;
}, false);

现在我有另一个问题。第二段代码中的return false定义在alert之后,为什么不阻止alert的调用呢?

如果我希望我的脚本完全控制点击事件(比如 return false,忽略其他脚本中定义的事件)怎么办?

最佳答案

What if I want my script to get total control of click event (like return false all the time disregarding events defined in other scripts)?

如果您可以先注册您的处理程序,那么您就可以这样做,前提是您使用的浏览器正确实现了 DOM3 事件(除非是 IE8 或更早版本,否则它可能会实现)。

这里(至少)涉及四件事:

  1. 防止默认。

  2. 停止传播到祖先元素。

  3. 停止调用相同 元素上的其他处理程序。

  4. 调用处理程序的顺序。

按顺序:

1。防止默认

这就是 DOM0 处理程序的 return false 所做的。 (详细信息:The Story on Return False。)DOM2 和 DOM3 中的等价物是 preventDefault。 :

document.addEventListener("click", function(e) {
    e.preventDefault();
}, false);

防止默认值可能与您正在做的事情并不完全相关,但由于您在 DOM0 处理程序中使用了 return false,并且这会阻止默认值,所以我将其包含在此处为了完整性。

2。停止传播到祖先元素

DOM0 处理程序没有办法做到这一点。 DOM2 的,通过 stopPropagation :

document.addEventListener("click", function(e) {
    e.stopPropagation();
}, false);

但是 stopPropagation 不会阻止同一元素上的其他处理程序被调用。来自 the spec :

The stopPropagation method is used prevent further propagation of an event during event flow. If this method is called by any EventListener the event will cease propagating through the tree. The event will complete dispatch to all listeners on the current EventTarget before event flow stops.

(我的重点。)

3。停止调用相同 元素上的其他处理程序

当然,这不会出现在 DOM0 上,因为对于同一元素上的同一事件, 不可能有其他处理程序。 :-)

据我所知,在 DOM2 中没有办法做到这一点,但 DOM3 给了我们 stopImmediatePropagation :

document.addEventListener("click", function(e) {
    e.stopImmediatePropagation();
}, false);

一些库为通过库连接的处理程序提供此功能(即使在 IE8 等非 DOM3 系统上),请参见下文。

4。调用处理程序的顺序

同样,与 DOM0 无关,因为不可能有其他处理程序。

在 DOM2 中,规范明确说附加到元素的处理程序的调用顺序是无法保证的;但是 DOM3 改变了这一点,表示处理程序按照它们注册的顺序被调用。

首先,来自DOM2 Section 1.2.1 :

Although all EventListeners on the EventTarget are guaranteed to be triggered by any event which is received by that EventTarget, no specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget.

但这被 DOM3 取代 Section 3.1 :

Next, the implementation must determine the current target's candidate event listeners. This must be the list of all event listeners that have been registered on the current target in their order of registration.

(我的重点。)

一些图书馆保证顺序,前提是您将事件与图书馆 Hook 。

同样值得注意的是,在 Microsoft 的 DOM2 前身(例如 attachEvent)中,它与 DOM3 的顺序相反:处理程序以相反注册顺序调用.


因此将#3 和#4 放在一起,如果您可以先注册您的处理程序,它将首先被调用,您可以使用 stopImmediatePropagation 来防止其他处理程序被调用。前提是浏览器正确实现了 DOM3。


所有这些(包括 IE8 和更早版本甚至不实现 DOM2 事件,更不用说 DOM3 的事实)是人们使用像 jQuery 这样的库的一个原因,其中一些确实保证顺序(只要一切都连接起来他们的处理程序通过有问题的库)并提供方法来阻止同一元素上的其他处理程序被调用。 (例如,对于 jQuery,顺序是它们被附加的顺序,您可以使用 stopImmediatePropagation 来停止对其他处理程序的调用。但我不想在这里推销 jQuery,只是解释一些库提供了比基本 DOM 内容更多的功能。)

关于javascript - 多个 addEventListener 如何在 JavaScript 中工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16273635/

有关javascript - 多个 addEventListener 如何在 JavaScript 中工作?的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  3. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  8. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  9. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  10. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

随机推荐