首页 > 解决方案 > 如何捕获自定义事件?

问题描述

我正在尝试创建一个自定义事件并捕获该事件。这是我简化的 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>

在这种情况下,我收到警报“父母”,但我没有收到子弹出窗口。

但是,如果我尝试使用已经存在的事件,如“点击”,它会起作用。

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>

有什么方法/解决方法可以用来捕获自定义事件吗?

标签: javascripthtmldom-eventsaddeventlistenercustom-events

解决方案


正如莫里茨所说,您需要在孩子身上触发事件,因为它是最内部的元素。这样,事件就会冒泡到每个父母。事件的target将始终是子元素,但currentTarget事件的将是当前元素,因为它沿链向上。

您必须确保,useCapture对于true您希望为其选取事件的祖先元素。见:EventTarget.addEventListener

useCapture

ABoolean表示这种类型的事件将在被分派到DOM 树中它下面的listener任何事件之前被分派给已注册的。EventTarget

通过树向上冒泡的事件不会触发指定使用捕获的侦听器。事件冒泡和捕获是传播嵌套在另一个元素中的元素中发生的事件的两种方式,当两个元素都注册了该事件的句柄时。事件传播模式确定元素接收事件的顺序。有关详细说明,请参阅 DOM Level 3 事件和 JavaScript 事件顺序。如果未指定,则useCapture默认为false.

如果您从 中删除useCapture参数(第二个参数)parent.addEventListener,则只有祖父母会被接走,跟随孩子。它不会破坏链条,除非您取消孩子中的事件。

注意:如果要触发非本地事件,最好使用CustomEvent构造函数。同样,如果需要,您可以直接调用构造函数。这只是一个浏览器安全的包装器。

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>


推荐阅读