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.
3 Réponses :
// 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
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).
La propriété Ce à quoi je peux penser est d'obtenir la cible élément, vérifiez si a un attribut Par conséquent : 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. 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 .
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);
}
});
À 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); }); });
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! :)