Comment faire pour que l'événement click se déclenche UNIQUEMENT sur le parent DIV, pas sur les enfants?

211

J'ai un DIV avec une classe foobar, et quelques DIV à l'intérieur de cette DIV qui ne sont pas classés, mais je suppose qu'ils héritent de la foobarclasse:

$('.foobar').on('click', function() { /*...do stuff...*/ });

Je veux que cela ne se déclenche qu'en cliquant quelque part dans le DIV mais pas sur ses DIVs enfants.

CaptSaltyJack
la source

Réponses:

440

Si le e.targetest le même élément que this, vous n'avez pas cliqué sur un descendant.

$('.foobar').on('click', function(e) {
  if (e.target !== this)
    return;
  
  alert( 'clicked the foobar' );
});
.foobar {
  padding: 20px; background: yellow;
}
span {
  background: blue; color: white; padding: 8px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class='foobar'> .foobar (alert) 
  <span>child (no alert)</span>
</div>

1106925
la source
Cette réponse explique ce commentaire
gdoron soutient Monica le
@gdoron: Adam est trop gentil. :)
1
Salut @vicky. Pour info, JavaScript propose deux types différents de comparaison d'égalité de valeur. Le ===ou !==utilise le "Strict Equality Comparison Algorithm" , tandis que le ==et !=utilise le "Abstract Equality Comparison Algorithm" , qui est de type coercitif. La sagesse générale est de toujours utiliser une comparaison stricte, sauf s'il existe un besoin spécifique pour le type coercitif (car ses règles sont un peu complexes) . Dans ce cas, parce que les objets sont comparés, cela ne fait vraiment aucune différence, mais vous constaterez que la plupart des gens resteront fidèles à la comparaison stricte .
1
@vicky: C'est bon. C'est toujours correct. Juste vous laisser JS a les différents opérateurs. ;-)
3
C'est une bonne réponse car elle peut également fonctionner avec Vanilla JS addEventListener et n'est pas spécifique à jQuery.
Michael Giovanni Pumo
64

Il existe une autre méthode qui fonctionne si cela ne vous dérange pas de cibler uniquement les nouveaux navigateurs. Ajoutez simplement le CSS

pointer-events: none;

à tous les enfants du div que vous souhaitez capturer le clic. Voici les tables de support

http://caniuse.com/#feat=pointer-events

Hobberwickey
la source
13
Sachez que je devrais éviter d'écrire des commentaires de «merci», mais je peux vous embrasser le pied pour cela :-)
Simona Adriani
@SimonaAdriani hein?
n3wb
Merci, j'ai fait la même chose, mais j'ai du mal à écrire un cas de test unitaire autour. Comment puis-je m'assurer que le clickdéclencheur d'événement de clic programmé doit être bloqué?
Pankaj Parkar
29

Vous pouvez utiliser le bullage en votre faveur:

$('.foobar').on('click', function(e) {
    // do your thing.
}).on('click', 'div', function(e) {
    // clicked on descendant div
    e.stopPropagation();
});
ou Je
la source
Cela ressemble à une bonne solution pour mon scénario spécifique, car je souhaite uniquement exclure les clics sur les <a>éléments descendants . Il n'y a qu'un seul problème: lorsque je clique au milieu sur eux, l'événement se déclenche toujours (testé dans Google Chrome). Existe-t-il une variante de cela qui empêche également cela?
cgogolin
@cgogolin, jetez un œil à ceci: stackoverflow.com/questions/12197122/…
Jessica
28

Je n'ai pas obtenu la réponse acceptée au travail, mais cela semble faire l'affaire, au moins dans la vanille JS.

if(e.target !== e.currentTarget) return;
Jens Törnell
la source
1
e.currentTarget est plus précis que le référencement, thiscar l'objet qui thispointe peut changer en fonction de la portée et du contexte d'où il est appelé
eballeste
20
//bind `click` event handler to the `.foobar` element(s) to do work,
//then find the children of all the `.foobar` element(s)
//and bind a `click` event handler to them that stops the propagation of the event
$('.foobar').on('click', function () { ... }).children().on('click', function (event) {
    event.stopPropagation();
    //you can also use `return false;` which is the same as `event.preventDefault()` and `event.stopPropagation()` all in one (in a jQuery event handler)
});

Cela arrêtera la propagation (propagation) de l' clickévénement sur l'un des éléments enfants de l'élément ou des .foobaréléments afin que l'événement n'atteigne pas le.foobar éléments pour déclencher leur ou leurs gestionnaires d'événements.

Voici une démo: http://jsfiddle.net/bQQJP/

Jaspe
la source
3
$(".advanced ul li").live('click',function(e){
    if(e.target != this) return;
    //code
    // this code will execute only when you click to li and not to a child
})
Michalis
la source
2

J'ai eu le même problème et j'ai trouvé cette solution (basée sur les autres réponses)

 $( ".newsletter_background" ).click(function(e) {
    if (e.target == this) {
        $(".newsletter_background").hide();
    } 
});

Fondamentalement, il dit que si la cible est le div, exécutez le code, sinon ne faites rien (ne le cachez pas)

Wonx2150
la source
1

Mon cas est similaire mais c'est l'occasion où vous en avez peu foobar -s et que vous ne souhaitez fermer qu'un seul - par un clic:

Trouver le cas parent

$(".foobar-close-button-class").on("click", function () {
    $(this).parents('.foobar').fadeOut( 100 );
    // 'this' - means that you finding some parent class from '.foobar-close-button-class'
    // '.parents' -means that you finding parent class with name '.foobar'
});

Trouver un enfant

$(".foobar-close-button-class").on("click", function () {
    $(this).child('.foobar-close-button-child-class').fadeOut( 100 );
    // 'this' - means that you finding some child class from '.foobar-close-button-class'
    // '.child' -means that you finding child class with name '.foobar-close-button-child-class'
});
Wukadin
la source
1

Vous pouvez utiliser event.currentTarget. Il ne cliquera que sur l'événement qui a reçu l'événement.

target = e => {
    console.log(e.currentTarget);
  };
<ul onClick={target} className="folder">
      <li>
        <p>
          <i className="fas fa-folder" />
        </p>
      </li>
    </ul>

Dejan Markovic
la source
1

Si vous ne pouvez pas utiliser pointer-events: none;et ciblez des navigateurs modernes, vous pouvez utiliser composedPathpour détecter un clic direct sur l'objet comme ceci:

element.addEventListener("click", function (ev) {
    if (ev.composedPath()[0] === this) {
        // your code here ...
    }
})

Vous pouvez en savoir plus sur compoundPath ici: https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath

Xenxier
la source
0

// if its li get value 
document.getElementById('li').addEventListener("click", function(e) {
                if (e.target == this) {
                    UodateNote(e.target.id);
                }
                })
                
                
                function UodateNote(e) {

    let nt_id = document.createElement("div");
    // append container to duc.
    document.body.appendChild(nt_id);
    nt_id.id = "hi";
    // get conatiner value . 
    nt_id.innerHTML = e;
    // body...
    console.log(e);

}
li{
 cursor: pointer;
    font-weight: bold;
  font-size: 20px;
    position: relative;
    width: 380px;
    height: 80px;
    background-color: silver;
    justify-content: center;
    align-items: center;
    text-align: center;
    margin-top: 0.5cm;
    border: 2px solid purple;
    border-radius: 12%;}
    
    p{
     cursor: text;
  font-size: 16px;
   font-weight: normal;
    display: block;
    max-width: 370px;
    max-height: 40px;
    overflow-x: hidden;}
<li id="li"><p>hi</p></li>

Omar bakhsh
la source