如何捕获自定义事件?

How to capture custom events?

我正在尝试创建自定义事件并捕获该事件。这是我简化的 HTML 和 JavaScript

let parent = document.getElementById('parent');
let child = document.getElementById('child');

parent.addEventListener('custom-event', () => alert("parent"), true);
child.addEventListener('custom-event', () => alert("child"));

let event = new Event('custom-event');
parent.dispatchEvent(event);
<div id="parent">
  <p id="child">
    Hello World
  </p>
</div>

在这种情况下,我收到警报 "parent",但随后我没有收到子弹出窗口。

但是,如果我尝试使用已经存在的事件,例如 "click",它会起作用。

let parent = document.getElementById('parent');
let child = document.getElementById('child');

parent.addEventListener('click', () => alert("parent"), true);
child.addEventListener('click', () => alert("child"));
<div id="parent">
  <p id="child">
    Hello World
  </p>
</div>

有什么 way/work 可以用来捕获自定义事件吗?

尝试在子节点上调度事件,您将收到两个警报。

let parent = document.getElementById('parent');
let child = document.getElementById('child');

parent.addEventListener('custom-event', () => alert("parent"), true);
child.addEventListener('custom-event', () => alert("child"));

let event = new Event('custom-event');
child.dispatchEvent(event);
<div id="parent">
  <p id="child">
    Hello World
  </p>
</div>

正如 Moritz 所说,您需要在 child 上触发事件,因为它是 most-inner 元素。这样事件就会冒泡到每个 parent。事件的 target 将始终是 child,但事件的 currentTarget 将是链上的当前元素。

您必须确保 useCapturetrue,对于您希望事件是 picked-up 的祖先元素。参见:EventTarget.addEventListener.

useCapture

A Boolean indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.

Events that are bubbling upward through the tree will not trigger a listener designated to use capture. Event bubbling and capturing are two ways of propagating events that occur in an element that is nested within another element, when both elements have registered a handle for that event. The event propagation mode determines the order in which elements receive the event. See DOM Level 3 Events and JavaScript Event order for a detailed explanation. If not specified, useCapture defaults to false.

如果从 parent.addEventListener 中删除 useCapture 参数(第二个参数),只有 grand-parent 会在 child 之后得到 picked-up。它不会破坏链条,除非您在 child.

中取消事件

注意:如果是触发non-native事件,最好使用CustomEvent构造函数。同样,如果需要,您可以直接调用构造函数。这只是一个 browser-safe 包装器。

let grandParent = document.getElementById('x-grand-parent');
let parent = document.getElementById('x-parent');
let child = document.getElementById('x-child');

grandParent.addEventListener('custom-event', (e) => console.log(e.currentTarget.id), true);
parent.addEventListener('custom-event', (e) => console.log(e.currentTarget.id), true);
child.addEventListener('custom-event', (e) => console.log(e.currentTarget.id));

triggerCustomEvent(child, 'custom-event');

function triggerCustomEvent(el, eventName, options) {
  let opts = Object.assign({
    canBubble: true,
    cancelable: true,
    detail: {}
  }, options);
  let event = null;
  if (window.CustomEvent && typeof window.CustomEvent === 'function') {
    event = new CustomEvent(eventName, {
      detail: opts.detail
    });
  } else {
    event = document.createEvent('CustomEvent');
    event.initCustomEvent(eventName, opts.canBubble, opts.cancelable, opts.detail);
  }
  el.dispatchEvent(event);
}
<div id="x-grand-parent">
  <div id="x-parent">
    <p id="x-child">
      Hello World
    </p>
  </div>
</div>