最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Event listener for when child of parent is clicked - Stack Overflow

programmeradmin1浏览0评论

I currently have an issue where I want to be able to check when a event is click. I want to use event delegation for this and so I have setup an event listener on a parent div, which listens for clicks:

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

This is my 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>

I want to be able to get the data-page attribute when the right div is clicked, ie when the div dashboard-shortcut is clicked. Is there any way that I can do this?

Thank you very much in advance.

I currently have an issue where I want to be able to check when a event is click. I want to use event delegation for this and so I have setup an event listener on a parent div, which listens for clicks:

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

This is my 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>

I want to be able to get the data-page attribute when the right div is clicked, ie when the div dashboard-shortcut is clicked. Is there any way that I can do this?

Thank you very much in advance.

Share Improve this question edited Sep 29, 2019 at 19:34 Asons 87.4k12 gold badges118 silver badges174 bronze badges asked Sep 29, 2019 at 17:37 dan123123dan123123 972 silver badges11 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

Unless you expect to have elements added dynamically, don't use event delegation, simply attach a listener on each target, in this case the .side-nav > [data-page] elements.

With that you avoid all detection issues, like which actual div where clicked etc., where this will be the targeted element, e.g. this.dataset.page.

...and a bonus; less code, less error prone, easier maintenance.

Note, you used data.set.param, should be dataset.param, where param here is page (data-page)

Stack snippet

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>


Based on a ment, where OP said they do load elements dynamically, added a 2nd sample.

Using if (e.target !== this && this.contains(e.target)) we can check so it is not the .side.nav itself (e.target !== this) someone clicked on, but one of its children (this.contains(e.target)), before continue.

And if, with e.target.closest('[data-page]').dataset.page we get the targeted element.

Note, as mentioned in another ment, if you have nested .side-nav with children having the same classes/attribute, you might need to adjust, where e.g. extending the selector for closest(), to closest('.side-nav > [data-page]'), should be enough, still, difficult to say with certainty.

Stack snippet

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>

// use closest method for finding actual element

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"));
    }
});

Note: prevent stop finding element till root

<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>

The target property of an event will be the element clicked. In your scenario the element clicked can be any HTML element you shown in your example: The p or the i inside the .side-nav-button, the .side-nav-button itself or even the .side-nav where you attach the event.

What I can think of is to get the target element, check if has a data-page attribute and if not, go for the parent and repeat the check. This way if, for example, the i element is clicked, it will check itself, then will check the p and finally its .side-nav-button.

Hence:

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);
    }
});
发布评论

评论列表(0)

  1. 暂无评论