1
votes

Écouteur d'événement lorsque l'utilisateur clique sur l'enfant du parent

J'ai actuellement un problème où je veux pouvoir vérifier quand un événement est un clic. Je souhaite utiliser la délégation d'événements pour cela et j'ai donc configuré un écouteur d'événements sur un div parent, qui écoute les clics:

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

Voici mon DOM:

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

Je veux pouvoir obtenir l'attribut data-page lorsque le div droit est cliqué, c'est-à-dire lorsque le div dashboard-shortcut est cliqué. Est-ce que je peux faire cela d'une manière ou d'une autre?

Merci d'avance.


0 commentaires

3 Réponses :


0
votes

// utilisez la méthode la plus proche pour trouver l'élément réel

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

Remarque: empêchez de ne pas trouver l'élément jusqu'à la racine

XXX


7 commentaires

S'il y a un élément au-delà de .side-nav avec cet attribut et que seul .side-nav est cliqué (ce qui peut arriver si vous avez des rembourrages et autres), vous vous tromperez page de données . EDIT: Je n'ai pas remarqué le truc root . Assez intelligent.


Cela est facilement résolu avec e.target.closest (". Side-nav> [data-page]")


Et pas besoin d'utiliser une astuce supplémentaire comme avec 'root' , simplement e.target! == this corrigez ça


@LGSon S'il y a un nav dans un nav (plus habituel que vous ne le pensez), alors c'est aussi cassé (en parlant du sélecteur CSS). La chose this est meilleure dans ce cas.


@ JorgeFuentesGonzález Si vous regardez le sélecteur, vous verrez que j'ai utilisé le sélecteur enfant > , qui résout le cas des éléments imbriqués.


@LGSon Vérifiez ceci: jsfiddle.net/omc0ebqr il a un navigateur imbriqué qui échoue. Avec votre truc this ou Sandeep root , il est résolu.


@ JorgeFuentesGonzález Eh bien, il y a toujours des cas extrêmes (si par exemple vous utilisez la même convention de nom dans tous les niveaux, lequel ne devrait pas), et quand, ils sont connus et peuvent être traités ... donc à cause de cela, j'en ai posté un qui rend les choses beaucoup plus faciles (et à mon humble avis est le moyen le plus approprié de le faire).



0
votes

La propriété target d'un événement sera l'élément cliqué. Dans votre scénario, l'élément sur lequel vous avez cliqué peut être n'importe quel élément HTML que vous avez montré dans votre exemple: le p ou le i à l'intérieur du .side-nav-button code >, le .side-nav-button lui-même ou même le .side-nav où vous attachez l'événement.

Ce à quoi je peux penser est d'obtenir la cible élément, vérifiez si a un attribut data-page et sinon, allez pour le parent et répétez la vérification. De cette façon, si, par exemple, on clique sur l'élément i , il se vérifiera, puis vérifiera le p et enfin son .side-nav-button .

Par conséquent :

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 commentaires

3
votes

À moins que vous ne vous attendiez à ce que des éléments soient ajoutés dynamiquement, n'utilisez pas la délégation d'événements, attachez simplement un écouteur sur chaque cible, dans ce cas les éléments .side-nav> [data-page] .

Avec cela, vous évitez tous les problèmes de détection, comme le div réel sur lequel vous avez cliqué, etc., où ce sera l'élément ciblé, par exemple this.dataset.page.

... et un bonus; moins de code, moins d'erreurs, une maintenance plus facile.

Remarque, vous avez utilisé data.set.param , devrait être dataset.param , où param ici est page ( data-page )

Stack snippet p>

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

Sur la base d'un commentaire, où OP a dit qu'il charge les éléments dynamiquement, a ajouté un deuxième échantillon.

En utilisant if (e.target! == this && this.contains (e.target)) nous pouvons vérifier si ce n'est pas le .side.nav lui-même ( e.target! == this ) quelqu'un cliqué sur, mais l'un de ses enfants ( this.contains (e.target) ), avant de continuer.

Et si, avec e.target.closest (' [data-page] '). dataset.page nous obtenons l'élément ciblé.

Notez, comme mentionné dans un autre commentaire, si vous avez imbriqué .side-nav avec des enfants ayant les mêmes classes / attributs, vous devrez peut-être ajuster, où par exemple étendre le sélecteur de plus proche () , à plus proche ('. side-nav> [data-page]') , devrait être suffisant, encore, difficile à dire avec certitude .

Extrait de pile

<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>
document.querySelectorAll('.side-nav > [data-page]').forEach(el => {
  el.addEventListener('click', function() {
    console.log(this.dataset.page);
  });
});


7 commentaires

Désolé, j'aurais dû le mentionner, je m'attends à ce que les éléments soient ajoutés de manière dynamique.


@ dan123123 Mise à jour et ajout d'un deuxième exemple, qui fonctionne avec les enfants ajoutés dynamiquement de .side-nav .


Pourquoi ne pas utiliser [... this.children] .includes (e.target) au lieu de e.target! == this && this.contains (e.target) ? Imo plus court et plus lisible.


@connexo Merci, plus court, oui, plus lisible, ... dépend de qui vous demandez :)


@LGSon désolé de ne pas revenir plus tôt - Fonctionne parfaitement, merci! Je l'ai ajouté comme réponse acceptée :)


@ dan123123 Merci ... et ne vous inquiétez pas de la rapidité avec laquelle vous répondez / revenez. Prenez toujours le temps dont vous avez besoin pour tester et déterminer quelle réponse fonctionne le mieux, et lorsque vous avez terminé, vous acceptez et / ou votez pour les réponses.


@LGSon c'est très gentil, merci :). Encore une fois, merci beaucoup pour votre temps et vos efforts pour ce post, cela m'a vraiment aidé. Merci beaucoup! :)