单击父项的子项时的事件侦听器

Event listener for when child of parent is clicked

我目前遇到一个问题,我希望能够检查点击事件的时间。我想为此使用事件委托,所以我在父 div 上设置了一个事件监听器,它监听点击:

document.querySelector('.side-nav').addEventListener('click', e => {
    console.log(e.target.data.set.param);
});

这是我的 DOM:

<div class="side-nav">
    <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
        <p class="side-nav-button-icon"><i class="fas fa-home"></i></p>
    </div>
    <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
        <p class="side-nav-button-icon"><i class="fas fa-cross"></i></p>
    </div>
</div>

我希望在点击右边的div时,即点击div dashboard-shortcut时,能够得到data-page属性。有什么办法可以做到这一点吗?

非常感谢您。

// 使用最近 方法查找实际元素

document.querySelector('.side-nav').addEventListener('click', e => {
    var elem = e.target.closest("[data-page]");
    if (elem && elem.getAttribute('data-page') !== 'root') {
        console.log(elem.getAttribute("data-page"));
    }
});

注意:防止停止查找元素直到根

<div class="side-nav" data-page='root'>
    <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
        <p class="side-nav-button-icon"><i class="fas fa-home"></i></p>
    </div>
   <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
        <p class="side-nav-button-icon"><i class="fas fa-cross"></i></p>
    </div>
</div>

事件的target 属性 将是被点击的元素。在您的场景中,单击的元素可以是您在示例中显示的任何 HTML 元素:p.side-nav-button 内的 i.side-nav-button 本身或甚至 .side-nav 您附加事件的地方。

我能想到的是获取目标元素,检查是否具有 data-page 属性,如果没有,则查找父元素并重复检查。这样,如果单击 i 元素,它将检查自身,然后检查 p,最后检查其 .side-nav-button.

因此:

document.querySelector('.side-nav').addEventListener('click', e => {
    let el = e.target;
    // The loop will stop when there's a page dataset
    // Also will stop when the element that is checking is .side-nav (event.currentTarget), as there's no need to check beyond that.
    while(el && el != event.currentTarget && !el.dataset.hasOwnProperty("page")) {
        el = el.parentNode;
    }
    let page = el && el.dataset.page;
    if (page) {
        console.log(page);
    }
});

除非您希望动态添加元素,否则不要使用事件委托,只需在每个目标上附加一个侦听器,在本例中为 .side-nav > [data-page] 个元素。

这样你就避免了所有的检测问题,比如点击了哪个实际的 div 等,其中 this 将是目标元素,例如this.dataset.page.

...还有奖金;更少的代码,更不容易出错,更容易维护。

注意,你用的data.set.param,应该是dataset.param,这里的parampage(data-page)

堆栈片段

document.querySelectorAll('.side-nav > [data-page]').forEach(el => {
  el.addEventListener('click', function() {
    console.log(this.dataset.page);
  });
});
<div class="side-nav">
    <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
        <p class="side-nav-button-icon"><i class="fas fa-home">Home</i></p>
    </div>
    <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
        <p class="side-nav-button-icon"><i class="fas fa-cross">Page2</i></p>
    </div>
</div>


根据评论,OP 说他们确实动态加载元素,添加了第二个示例。

使用 if (e.target !== this && this.contains(e.target)) 我们可以检查它不是有人点击的 .side.nav 本身 (e.target !== this),而是其中一个 children (this.contains(e.target)), 在继续之前。

并且如果使用 e.target.closest('[data-page]').dataset.page 我们得到了目标元素。

请注意,如另一条评论所述,如果您嵌套了 .side-nav 和具有相同 classes/attribute 的 children,您可能需要进行调整,例如将 closest() 的选择器扩展到 closest('.side-nav > [data-page]') 应该就足够了,但仍然很难确定。

堆栈片段

document.querySelector('.side-nav').addEventListener('click', function(e) {
  if (e.target !== this && this.contains(e.target)) {    
    console.log(e.target.closest('[data-page]').dataset.page);  
  }
});
<div class="side-nav">
    <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
        <p class="side-nav-button-icon"><i class="fas fa-home">Home</i></p>
    </div>
    <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
        <p class="side-nav-button-icon"><i class="fas fa-cross">Page2</i></p>
    </div>
</div>