Come posso evitare che l'evento onclick di un genitore venga generato quando si fa clic su un'ancora figlio?


348

Attualmente sto usando jQuery per rendere selezionabile un div e in questo div ho anche delle ancore. Il problema in cui mi imbatto è che quando faccio clic su un'ancora vengono attivati ​​entrambi gli eventi clic (per il div e l'ancora). Come posso evitare che l'evento onclick del div si attivi quando si fa clic su un'ancora?

Ecco il codice rotto:

JavaScript

var url = $("#clickable a").attr("href");

$("#clickable").click(function() {
    window.location = url;
    return true;
})

HTML

<div id="clickable">
    <!-- Other content. -->
    <a href="http://foo.com">I don't want #clickable to handle this click event.</a>
</div>

Risposte:


460

Gli eventi si spostano nel punto più alto del DOM in cui è stato associato un evento clic. Quindi, nel tuo esempio, anche se non ci fossero altri elementi esplicitamente cliccabili nel div, ogni elemento figlio del div farebbe il loro evento click nel DOM fino a quando il gestore di eventi click del DIV lo catturerà.

Esistono due soluzioni per verificare chi ha effettivamente generato l'evento. jQuery passa un oggetto eventargs insieme all'evento:

$("#clickable").click(function(e) {
    var senderElement = e.target;
    // Check if sender is the <div> element e.g.
    // if($(e.target).is("div")) {
    window.location = url;
    return true;
});

Puoi anche collegare un gestore di eventi click ai tuoi link che dicono loro di interrompere il gorgoglio degli eventi dopo l'esecuzione del loro gestore:

$("#clickable a").click(function(e) {
   // Do something
   e.stopPropagation();
});

3
Bella risposta. Bello sapere che ci sono anche opzioni.
Jonathon Watney,

4
+1! Collegare un gestore di clic con stopPropagation è un trucco molto carino, grazie!
Thomas

2
se avessi un mucchio di elementi su cui vuoi impedire la propagazione, potresti trovare il loro elemento genitore e la testa impedire che anche esso bolle. Quindi, piuttosto che intercettare tutti i collegamenti a in un div, per esempio, diciamo: basta intercettare il clic anche sul div stesso e impedirgli di andare più in alto e sei pronto.
sucitivel

21
Usare if( e.target !== this) return;nel genitore è meglio che e.stopPropagation()nel figlio poiché non si sa mai se qualcun altro attacca un gestore ai figli o se una biblioteca deve associare un gestore a un figlio (e non si desidera fare confusione con il codice della biblioteca). È una migliore separazione delle preoccupazioni.
UTF_or_Death

3
Mettere il if( e.target !== this) return;segno di spunta nel genitore significa che se si fa clic su uno qualsiasi degli altri figli di quel genitore che non hanno gestori onClick propri, allora non succede nulla. Quindi è inutile per una situazione in cui hai ad esempio un div genitore cliccabile. e.stopPropagation()funziona bene comunque.
derf26,

101

Usa il metodo stopPropagation , vedi un esempio:

$("#clickable a").click(function(e) {
   e.stopPropagation();
});

Come detto da jQuery Docs:

stopPropagation Il metodo impedisce all'evento di gorgogliare l'albero del DOM, impedendo a qualsiasi gestore padre di essere informato dell'evento.

Tieni presente che non impedisce ad altri ascoltatori di gestire questo evento (es. Più di un gestore di clic per un pulsante), se non è l'effetto desiderato, devi stopImmediatePropagationinvece utilizzare .


48

Ecco la mia soluzione per tutti quelli che cercano un codice non jQuery (javascript puro)

document.getElementById("clickable").addEventListener("click", function( e ){
    e = window.event || e; 
    if(this === e.target) {
        // put your code here
    }
});

Il tuo codice non verrà eseguito se cliccato sui figli dei genitori


1
Questo ha funzionato per me, avevo bisogno di una soluzione non JS / jQuery. 10x!
LA,

Bella risposta. Ho appena passato l'evento direttamente. Quindi non ho usato window.event, cosa che MDN scoraggia: developer.mozilla.org/en-US/docs/Web/API/Window/event . Se riesci a risparmiare tempo, ti sarei grato se potessi commentare il motivo per cui hai usato window.event(forse è un problema che esisteva nel 2015 o non ho capito il motivo).
RMo

15

puoi anche provare questo

$("#clickable").click(function(event) {
   var senderElementName = event.target.tagName.toLowerCase();
   if(senderElementName === 'div')
   {
       // do something here 
   } 
   else
   {
      //do something with <a> tag
   }
});

14

Se non hai intenzione di interagire con gli elementi interni in ogni caso, una soluzione CSS potrebbe essere utile per te.

Basta impostare l'elemento / i interno / i su pointer-events: none

nel tuo caso:

.clickable > a {
    pointer-events: none;
}

o per colpire tutti gli elementi interni in generale:

.clickable * {
    pointer-events: none;
}

Questo semplice hack mi ha fatto risparmiare molto tempo durante lo sviluppo con ReactJS

Il supporto del browser è disponibile qui: http://caniuse.com/#feat=pointer-events


8

Se hai più elementi nel div cliccabile, dovresti fare questo:

$('#clickable *').click(function(e){ e.stopPropagation(); });

8

L'uso return false;o e.stopPropogation();non consentirà l'esecuzione di ulteriore codice. Arresterà il flusso in questo punto stesso.


Sì, questo è importante - mi sono imbattuto in questo io. Ma la risposta sopra di Rex è utile: può ottenere l'elemento su cui è stato fatto clic e, in alcuni casi, utilizzarlo nella logica che si sta tentando di interrompere. .target.nodeName è stato anche utile per avere un'idea chiara di ciò che è stato colpito.
Watercayman,


4

Alternativa in linea:

<div>
    <!-- Other content. -->
    <a onclick='event.stopPropagation();' href="http://foo.com">I don't want #clickable to handle this click event.</a>
</div>

3

Ecco un esempio usando Angular 2+

Ad esempio, se si desidera chiudere un componente modale se l'utente fa clic all'esterno di esso:

// Close the modal if the document is clicked.

@HostListener('document:click', ['$event'])
public onDocumentClick(event: MouseEvent): void {
  this.closeModal();
}

// Don't close the modal if the modal itself is clicked.

@HostListener('click', ['$event'])
public onClick(event: MouseEvent): void {
  event.stopPropagation();
}

1

Devi impedire all'evento di raggiungere (gorgogliare) il genitore (il div). Vedi la parte relativa al gorgogliamento qui e informazioni API specifiche di jQuery qui .


Freddo. Grazie per le informazioni sul gorgoglio degli eventi.
Jonathon Watney,

1

var inner = document.querySelector("#inner");
var outer = document.querySelector("#outer");
inner.addEventListener('click',innerFunction);
outer.addEventListener('click',outerFunction);

function innerFunction(event){
  event.stopPropagation();
  console.log("Inner Functiuon");
}

function outerFunction(event){
  console.log("Outer Functiuon");
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Pramod Kharade-Event with Outer and Inner Progration</title>
</head>
<body>
<div id="outer" style="width:100px;height:100px;background-color:green;">
  <div id="inner" style="width:35px;height:35px;background-color:yellow;"></div>
</div>
</body>
</html>


0

Per specificare alcuni sotto-elementi come non cliccabili, scrivi la gerarchia CSS come nell'esempio sotto.

In questo esempio interrompo la propagazione a tutti gli elementi (*) all'interno di td all'interno di tr all'interno di una tabella con la classe ".subtable"

$(document).ready(function()
{    
   $(".subtable tr td *").click(function (event)
   {
       event.stopPropagation();
   });

});

0

ignoreParent () è una soluzione JavaScript pura.

Funziona come un livello intermedio che confronta le coordinate del clic del mouse con le coordinate dell'elemento / i figlio / i. Due semplici passaggi di implementazione:

1. Inserisci il codice ignoreParent () sulla tua pagina.

2. Invece dell'originale onclick del genitore = "parentEvent ();" , Scrivi:

onclick="ignoreParent(['parentEvent()', 'child-ID']);"

È possibile trasmettere ID di qualsiasi numero di elementi figlio alla funzione ed escluderne altri.

Se hai fatto clic su uno degli elementi figlio, l'evento principale non viene generato. Se si fa clic su parent, ma non su nessuno degli elementi child [forniti come argomenti], l'evento parent viene generato.

codice ignoreParent () su Github


0

Se è in un contesto integrato, in HTML prova questo:

onclick="functionCall();event.stopPropagation();

-1

Nel caso in cui qualcuno abbia riscontrato questo problema utilizzando React, è così che l'ho risolto.

SCSS:

#loginBackdrop {
position: absolute;
width: 100% !important;
height: 100% !important;
top:0px;
left:0px;
z-index: 9; }

#loginFrame {
width: $iFrameWidth;
height: $iFrameHeight;
background-color: $mainColor;
position: fixed;
z-index: 10;
top: 50%;
left: 50%;
margin-top: calc(-1 * #{$iFrameHeight} / 2);
margin-left: calc(-1 * #{$iFrameWidth} / 2);
border: solid 1px grey;
border-radius: 20px;
box-shadow: 0px 0px 90px #545454; }

Component's render ():

render() {
    ...
    return (
        <div id='loginBackdrop' onClick={this.props.closeLogin}>
            <div id='loginFrame' onClick={(e)=>{e.preventDefault();e.stopPropagation()}}>
             ... [modal content] ...
            </div>
        </div>
    )
}

Aggiungendo una funzione onClick per gli eventi modali secondari (div di contenuto) del mouse viene impedito di raggiungere la funzione 'closeLogin' dell'elemento genitore.

Questo ha funzionato per me e sono stato in grado di creare un effetto modale con 2 semplici div.


-3

aggiungere acome segue:

<a href="http://foo.com" onclick="return false;">....</a>

o return false;dal gestore di clic per #clickablelike:

  $("#clickable").click(function() {
        var url = $("#clickable a").attr("href");
        window.location = url;
        return false;
   });

-3

Tutte le soluzioni sono complicate e di jscript. Ecco la versione più semplice:

var IsChildWindow=false;

function ParentClick()
{
    if(IsChildWindow==true)
    {
        IsChildWindow==false;
        return;
    }
    //do ur work here   
}


function ChildClick()
{
    IsChildWindow=true;
    //Do ur work here    
}

3
penso che tu abbia commesso un errore nella riga "IsChildWindow == false;" - non dovrebbe essere "IsChildWindow = false;"?
Andre Schweighofer,

-5
<a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>

5
Ciò impedisce anche la navigazione del collegamento.
Rex M,

Sì o non è necessario? O hai bisogno di essere nevegar?
andres descalzo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.