parent 节点上的事件侦听器也在所有 children 节点上触发

Event listener on parent node is triggering on all children nodes too

我正在从头开始用 vanilla js 编写一个可拖动的 class(这与 jQuery 可拖动无关),它工作得很好,只有我的听众在 [=40= 上触发]ren 所选节点。我已经在侦听器内部尝试 e.stopPropagation(),但它似乎并没有改变结果。

这是 class 中的一段代码:

setListeners() {

    const targets = document.getElementsByClassName("-jsDraggable");

    [...targets].forEach(elem => {

        elem.addEventListener("mousemove", e => this.handleMouseMove(e));
        elem.addEventListener("mousedown", e => this.handleMouseDown(e));
        elem.addEventListener("mouseup", e => this.handleMouseUp(e));

    });
}

...例如:

<ul class="-jsDraggable">
    <li>No drag</li>
    <li>No drag</li>
    <li class="-jsDraggable">Can drag this item</li>
    <li>No drag</li>
</ul>

在这种情况下,我希望 <ul class="-jsDraggable">...</ul> 和内部的单个 <li class="-jsDraggable">...</li> 都受到影响,从其他列表项之一拖动只会拖动主 <ul class="-jsDraggable">...</ul>元素。

但是,无论我与哪个 child 节点交互,无论它在 DOM 中与具有 class 的节点相比有多远,它都会触发处理程序.

如有任何帮助,我们将不胜感激!

编辑:另一个需要说明的例子:

<article class="-jsDraggable">
    <header>
        <h1>Heading</h1>
    </header>
    <main>
        <p>...</p>
    </main>
</article>

无论我将这个 <article> 元素拖到哪里,它都应该将整个 HTML 组作为一个拖入(因为其中的 parent 都有 class).然而,目前它的表现更像这样:

<article class="-jsDraggable">
    <header class="-jsDraggable">
        <h1 class="-jsDraggable">Heading</h1>
    </header>
    <main class="-jsDraggable">
        <p class="-jsDraggable">...</p>
    </main>
</article>

...并且每个 child 也在移动,而它应该只移动附有 class 的 parent 容器。

如果我正确理解你的问题,那么一个选项(除其他外)是区分事件的来源,并通过 currentTargettarget 字段过滤事件处理 event 像这样的对象:

if(event.currentTarget === event.target) {
   /* The user is interacting with the actual -jsDraggable element */
}
else {
   /* The user is interacting with a descendant of a -jsDraggable element */
}

这实际上意味着,如果生成事件的元素(即 currentTarget)与事件处理程序绑定到的元素相同(即 target),那么我们确定该事件与实际的 -jsDraggable 元素本身有关(而不是后代)。这种方法补充了您当前的代码,如下所示:

function handleMouseMove(event) {
  if(event.currentTarget === event.target) {
    console.log(Date.now(), 'Mouse move over draggable');
  }
}
function handleMouseDown(event) {
  if(event.currentTarget === event.target) {
    console.log(Date.now(), 'Drag start on draggable');
  }
}
function handleMouseUp(event) {
  if(event.currentTarget === event.target) {
    console.log(Date.now(), 'Drag end on draggable');
  }
}

function setListeners() {

    const targets = document.querySelectorAll(".-jsDraggable");

    targets.forEach(elem => {

        elem.addEventListener("mousemove", e => handleMouseMove(e));
        elem.addEventListener("mousedown", e => handleMouseDown(e));
        elem.addEventListener("mouseup", e => handleMouseUp(e));

    });
}

setListeners();
ul {
  padding:1rem;
  background:lightgreen;
}
li {
  padding:1rem;
  background:pink;
}
.-jsDraggable {
  background:lightblue;
}
<ul class="-jsDraggable">
    <li>No drag</li>
    <li>No drag</li>
    <li class="-jsDraggable">Can drag this item</li>
    <li>No drag</li>
</ul>

我解决了它,它不起作用,因为我将当前元素设置为 this.elem = e.target 而不是 this.elem = e.currentTarget。此后,mousedown 中的 e.stopPropagation() 按预期工作。

感谢您让我了解 e.currentTarget,在阅读此线程中的帮助之前我并不知道它。