Jak sprawić, aby zdarzenie kliknięcia uruchamiało się TYLKO na rodzicielskim DIV, a nie dzieci?

211

Mam DIV z zaklasyfikowaną foobari kilka DIV wewnątrz tego DIV, które są niesklasyfikowane, ale przypuszczam, że dziedziczą foobarklasę:

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

Chcę, żeby wystrzelił tylko po kliknięciu gdzieś w DIV, ale nie w DIV-y jego dzieci.

CaptSaltyJack
źródło

Odpowiedzi:

439

Jeśli e.targetjest to ten sam element co this, nie kliknąłeś potomka.

$('.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
źródło
Ta odpowiedź wyjaśnia ten komentarz
gdoron wspiera Monikę
@gdoron: Adam jest zbyt miły. :)
1
Cześć @vicky. Tylko do twojej wiadomości, JavaScript ma dwa różne rodzaje porównania równości wartości. ===Lub !==wykorzystuje „ścisłej równości Porównanie Algorithm” , podczas gdy ==i !=używa „Streszczenie Równości Porównanie algorytmu” , czyli rodzaj przymusu. Ogólna mądrość polega na tym, aby zawsze stosować ścisłe porównanie, chyba że istnieje szczególna potrzeba użycia typu przymusu (ponieważ jego reguły są nieco skomplikowane) . W tym przypadku, ponieważ porównywane są obiekty, to naprawdę nie robi różnicy, ale przekonasz się, że większość ludzi nadal będzie przestrzegać ścisłego porównania.
1
@vicky: W porządku. To nadal jest poprawne. Pozwalając ci JS ma różnych operatorów. ;-)
3
To dobra odpowiedź, ponieważ może również współpracować z Vanilla JS addEventListener i nie jest specyficzna dla jQuery.
Michael Giovanni Pumo,
64

Jest inny sposób, który działa, jeśli nie masz nic przeciwko celowaniu w nowsze przeglądarki. Po prostu dodaj CSS

pointer-events: none;

do wszystkich dzieci div, które chcesz uchwycić kliknięcie. Oto tabele wsparcia

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

Hobberwickey
źródło
13
Wiedz, że powinienem unikać pisania komentarzy „dziękuję”, ale mogę cię za to pocałować :-)
Simona Adriani
@SimonaAdriani huh?
n3wb
Dzięki, postąpiłem w ten sam sposób, ale staram się napisać wokół niego test jednostkowy. Jak mogę się upewnić, że clickwyzwalacz programowego zdarzenia kliknięcia powinien być zablokowany?
Pankaj Parkar
29

Możesz użyć bulgotania na swoją korzyść:

$('.foobar').on('click', function(e) {
    // do your thing.
}).on('click', 'div', function(e) {
    // clicked on descendant div
    e.stopPropagation();
});
lub ja
źródło
To wygląda na dobre rozwiązanie dla mojego konkretnego scenariusza, ponieważ chcę tylko wykluczyć kliknięcia <a>elementów potomnych . Jest tylko jeden problem: kiedy klikam je środkowym przyciskiem, zdarzenie nadal się uruchamia (testowane w Google Chrome). Czy istnieje wariant, który również temu zapobiega?
cgogolin,
@cgogolin, spójrz na to: stackoverflow.com/questions/12197122/...
Jessica
28

Nie dostałem zaakceptowanej odpowiedzi do pracy, ale wydaje się, że to załatwia sprawę, przynajmniej w waniliowym JS.

if(e.target !== e.currentTarget) return;
Jens Törnell
źródło
1
e.currentTarget jest bardziej dokładne niż przedstawieniu this, ponieważ obiekt, który thiswskazuje zmiana może w zależności od zakresu i kontekstu, z którego jest on nazywany
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)
});

Spowoduje to zatrzymanie propagacji (propagacji) clickzdarzenia na dowolnym elemencie (-ach) .foobarelementu (-ach), aby zdarzenie nie dotarło do .foobarelementu (ów) w celu uruchomienia ich procedur obsługi zdarzeń.

Oto demo: http://jsfiddle.net/bQQJP/

Jaspis
źródło
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
źródło
2

Miałem ten sam problem i wymyśliłem to rozwiązanie (na podstawie innych odpowiedzi)

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

Zasadniczo mówi, że jeśli celem jest div, to uruchom kod, w przeciwnym razie nic nie rób (nie ukrywaj go)

Wonx2150
źródło
1

Mój przypadek jest podobny, ale jest to okazja, gdy masz kilka foobar-s i chcesz zamknąć tylko jeden - za jednym kliknięciem:

Znajdź przypadek rodzica

$(".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'
});

Znajdź skrzynkę dla dziecka

$(".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
źródło
1

Możesz użyć event.currentTarget. To zrobi zdarzenie kliknięcia tylko elemnt, który dostał zdarzenie.

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

Dejan Markovic
źródło
1

Jeśli nie możesz używać pointer-events: none;i celujesz w nowoczesne przeglądarki, możesz użyć composedPathdo wykrycia bezpośredniego kliknięcia obiektu w następujący sposób:

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

Możesz przeczytać więcej o compositePath tutaj: https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath

Xenxier
źródło
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
źródło