【问题标题】:How to ensure an EventListener is executed last?如何确保最后执行 EventListener?
【发布时间】:2017-12-17 23:26:54
【问题描述】:

我希望我添加到 EventTarget 的特定 EventListener 最后执行(但在默认操作之前)独立于它们在其中注册的顺序,附加约束是事件不可取消,意味着它只能被触发一次来达到这个目的。

我已经尝试在事件侦听器中使用 .addEventListener,但这只会注册一个 EventListener,以便在下次事件发生时执行,而不是在当前处理期间执行。 不幸的是,EventListenerList 从未成为 DOM 规范的一部分,这意味着它也不是使用 .stopImmediatePropagation 并在执行最后要执行的操作之前手动执行其他事件的选项。

我不是在寻找它们的执行顺序,我知道现代浏览器引擎按注册顺序执行 EventListener。我在询问绕过该行为的方法(可能仅在结果中)。

对此的具体需求是在内容脚本中(这意味着我无法控制添加的其他 EventListeners(或发生的顺序))在 URL 被使用之前重写它们 - 但是有些页面有 EventListeners在同一事件中他们自己的重写。

当前行为的一个例子:

// The content script:
document.getElementById("target").addEventListener("click",last);

function last() {
  this.innerHTML="Correct!";
  console.log("This is supposed to occur last.")
}


// The webpage:
document.getElementById("target").addEventListener("click",first);

function first() {
  this.innerHTML="Incorrect!";
  console.log("This is supposed to occur first.")
}
<button id="target">
Click me!
</button>

【问题讨论】:

  • 请提供代码
  • 不确定我是否理解,但也许您可以处理 URL 更改事件而不是点击事件
  • 这是不可能的,因为 URL 在 click 事件中发生了更改,并且只有在默认操作已经触发时,才能在该 click 事件之外观察此更改。

标签: javascript dom addeventlistener dom-events


【解决方案1】:

替代方法可能是处理所有点击事件并检查 event.target 是否是要处理的元素:

function first() { console.log('first') }
function second() { console.log('second') }
function last(e) { if (e.target.id === 'target') console.log('last') }

target.addEventListener("click", first);
document.body.addEventListener("click", last);
target.addEventListener("click", second);
<button id="target">
  Click me!
</button>

由于事件冒泡,按钮事件在其父事件之前执行。

【讨论】:

  • 太棒了,这似乎是一个可行的解决方案(至少对于确实冒泡的事件)!
【解决方案2】:

实现此目的的一种简单但绝不完全可靠的方法是将要最后发生的事件包装在 setTimeout() 中。这将导致其执行延迟。当然,如果在其他事件侦听器中有其他异步函数,您可能无法完全预测所需的延迟:

function last() {
  setTimeout( () => {
   this.innerHTML=("Correct!");
   console.log("This is supposed to occur last.")
  })
}


// The webpage:

document.getElementById("target").addEventListener("click",last);
document.getElementById("target").addEventListener("click",first);



function first() {
  this.innerHTML="Incorrect!";
  console.log("This is supposed to occur first.")
}
<button id="target">
Click me!
</button>

【讨论】:

  • 不幸的是,这会导致包装代码在默认操作之后执行,因此不会获得相同的结果(尤其是在应用于锚元素时)。不过,对于没有此要求的情况,这是一个很好的解决方案。
  • 您是要阻止默认操作还是 event.preventDefault 不适合您?
  • 我在问题中专门指的是不可取消的事件,这意味着 .preventDefault 在这里不是一个选项。
猜你喜欢
  • 2011-09-21
  • 1970-01-01
  • 2021-11-14
  • 2012-12-04
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多