Wie verhindere ich, dass das Onclick-Ereignis eines Elternteils ausgelöst wird, wenn auf einen untergeordneten Anker geklickt wird?

346

Ich verwende derzeit jQuery, um ein Div anklickbar zu machen, und in diesem Div habe ich auch Anker. Das Problem, auf das ich stoße, ist, dass beim Klicken auf einen Anker beide Klickereignisse ausgelöst werden (für div und anker). Wie verhindere ich, dass das Onclick-Ereignis des Div ausgelöst wird, wenn auf einen Anker geklickt wird?

Hier ist der kaputte Code:

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>
Jonathon Watney
quelle

Antworten:

458

Ereignisse sprudeln zum höchsten Punkt im DOM, an dem ein Klickereignis angehängt wurde. Selbst wenn Sie in Ihrem Beispiel keine anderen explizit anklickbaren Elemente im div hätten, würde jedes untergeordnete Element des div sein Klickereignis in das DOM sprudeln lassen, bis der Klickereignishandler des DIV es abfängt.

Hierfür gibt es zwei Lösungen: Überprüfen Sie, wer das Ereignis tatsächlich ausgelöst hat. jQuery übergibt ein eventargs-Objekt zusammen mit dem Ereignis:

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

Sie können Ihren Links auch einen Klickereignishandler hinzufügen, der sie auffordert, das Sprudeln von Ereignissen zu stoppen, nachdem ihr eigener Handler ausgeführt wurde:

$("#clickable a").click(function(e) {
   // Do something
   e.stopPropagation();
});
Rex M.
quelle
3
Gute Antwort. Gut zu wissen, dass es auch Optionen gibt.
Jonathon Watney
4
+1! Das Anhängen eines Klick-Handlers mit stopPropagation ist ein sehr schöner Trick, danke!
Thomas
2
Wenn Sie eine Reihe von Elementen hatten, auf denen Sie die Weitergabe verhindern wollten, konnten Sie das übergeordnete Element und den Kopf finden, um zu verhindern, dass es auch dort hochsprudelt. Anstatt also alle a-Links in einem Div abzufangen, sagen wir zum Beispiel, fangen Sie einfach den Klick sogar auf das Div selbst ab und verhindern Sie, dass es höher wird, und Sie sind fertig.
Erfolg
21
Die Verwendung if( e.target !== this) return;im übergeordneten Element ist besser als e.stopPropagation()im untergeordneten Element, da Sie nie wissen, ob jemand anderes einen Handler an die untergeordneten Elemente anfügt oder ob eine Bibliothek einen Handler an ein untergeordnetes Element anhängen muss (und Sie nicht mit dem Bibliothekscode herumspielen möchten). Es ist eine bessere Trennung von Bedenken.
UTF_or_Death
3
Wenn Sie den if( e.target !== this) return;Scheck in das übergeordnete Element einfügen, wird nichts passiert, wenn auf eines der anderen untergeordneten Elemente dieses übergeordneten Elements geklickt wird, für das keine eigenen onClick-Handler vorhanden sind. Es ist also nutzlos für eine Situation, in der Sie z. B. ein anklickbares übergeordnetes Div haben. e.stopPropagation()funktioniert aber gut.
derf26
100

Verwenden Sie die stopPropagation- Methode (siehe Beispiel):

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

Wie von jQuery Docs gesagt:

stopPropagation Die Methode verhindert, dass das Ereignis in den DOM-Baum sprudelt, und verhindert, dass übergeordnete Handler über das Ereignis benachrichtigt werden.

Beachten Sie, dass andere Listener nicht daran gehindert werden, dieses Ereignis zu behandeln (z. B. mehr als ein Klick-Handler für eine Schaltfläche). Wenn dies nicht der gewünschte Effekt ist, müssen Sie ihn stopImmediatePropagationstattdessen verwenden.

Cleiton
quelle
48

Hier meine Lösung für alle da draußen, die nach einem Nicht-jQuery-Code suchen (reines Javascript)

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

Ihr Code wird nicht ausgeführt, wenn Sie auf die Kinder der Eltern klicken

Sabaz
quelle
1
Dies funktionierte für mich, ich brauchte eine Nicht-JS / jQuery-Lösung. 10x!
LA
Gute Antwort. Ich habe die Veranstaltung gerade direkt bestanden. Also habe ich nicht verwendet window.event, was MDN entmutigt: developer.mozilla.org/en-US/docs/Web/API/Window/event . Wenn Sie Zeit sparen können, würde ich es begrüßen, wenn Sie kommentieren können, warum Sie verwendet haben window.event(möglicherweise handelt es sich um ein Problem, das 2015 bestand, oder ich habe den Grund nicht verstanden).
RMo
15

Sie können dies auch versuchen

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

Wenn Sie in keinem Fall beabsichtigen, mit dem / den inneren Element (en) zu interagieren, kann eine CSS-Lösung für Sie hilfreich sein.

Stellen Sie einfach die inneren Elemente auf ein pointer-events: none

in Ihrem Fall:

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

oder um alle inneren Elemente allgemein anzuvisieren:

.clickable * {
    pointer-events: none;
}

Dieser einfache Hack hat mir bei der Entwicklung mit ReactJS viel Zeit gespart

Browser-Unterstützung finden Sie hier: http://caniuse.com/#feat=pointer-events

Hooman Askari
quelle
8

Wenn das anklickbare Div mehrere Elemente enthält, sollten Sie Folgendes tun:

$('#clickable *').click(function(e){ e.stopPropagation(); });
Ivan Ivković
quelle
8

Wenn Sie weiteren Code verwenden return false;oder e.stopPropogation();nicht ausführen lassen. Es wird den Fluss an diesem Punkt selbst stoppen.

Imamudin Naseem
quelle
Ja, das ist wichtig - bin selbst darauf gestoßen. Die obige Antwort von Rex ist jedoch hilfreich - kann das angeklickte Element abrufen und in einigen Fällen in der Logik verwenden, die Sie stoppen möchten. .target.nodeName war auch hilfreich, um eine klare Vorstellung davon zu bekommen, was getroffen wurde.
Watercayman
8

Schreiben, wenn jemand braucht (für mich gearbeitet):

event.stopImmediatePropagation()

Aus dieser Lösung.

Bahadir Tasdemir
quelle
4

Inline-Alternative:

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

Hier ist ein Beispiel mit Angular 2+

Wenn Sie beispielsweise eine modale Komponente schließen möchten, wenn der Benutzer außerhalb der Komponente klickt:

// 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();
}
Steve Brush
quelle
1

Sie müssen verhindern, dass das Ereignis den Elternteil (den Div) erreicht (sprudelt). Sehen Sie den Teil über sprudelt hier und jQuery-spezifische API info hier .

Matt Ball
quelle
Cool. Vielen Dank für die Info über Event Bubbling.
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>

Pramod Kharade
quelle
0

Um ein Unterelement als nicht anklickbar anzugeben, schreiben Sie die CSS-Hierarchie wie im folgenden Beispiel.

In diesem Beispiel stoppe ich die Weitergabe an alle Elemente (*) innerhalb von td innerhalb von tr in einer Tabelle mit der Klasse ".subtable".

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

});
user3202819
quelle
0

ignoreParent () ist eine reine JavaScript-Lösung.

Es fungiert als Zwischenebene, die die Koordinaten des Mausklicks mit den Koordinaten der untergeordneten Elemente vergleicht. Zwei einfache Implementierungsschritte:

1. Fügen Sie den Code ignoreParent () auf Ihre Seite ein.

2. Anstelle des ursprünglichen onclick = "parentEvent ();" , schreiben:

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

Sie können IDs beliebig vieler untergeordneter Elemente an die Funktion übergeben und andere ausschließen.

Wenn Sie auf eines der untergeordneten Elemente geklickt haben, wird das übergeordnete Ereignis nicht ausgelöst. Wenn Sie auf übergeordnetes Element geklickt haben, jedoch nicht auf eines der untergeordneten Elemente [als Argumente angegeben], wird das übergeordnete Ereignis ausgelöst.

ignoreParent () Code auf Github

Fom
quelle
0

Wenn es sich um einen Inline-Kontext handelt, versuchen Sie in HTML Folgendes:

onclick="functionCall();event.stopPropagation();
Gleno
quelle
-1

Falls jemand dieses Problem mit React hatte, habe ich es so gelöst.

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

Render () der Komponente:

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

Durch Hinzufügen einer onClick-Funktion für das untergeordnete modale (content div) Mausklickereignis wird verhindert, dass die Funktion 'closeLogin' des übergeordneten Elements erreicht wird.

Dies hat den Trick für mich getan und ich konnte einen Modaleffekt mit 2 einfachen Divs erzeugen.

Claudio
quelle
-3

awie folgt hinzufügen :

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

oder return false;vom Klick-Handler für #clickablewie:

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

Alle Lösungen sind kompliziert und von jscript. Hier ist die einfachste Version:

var IsChildWindow=false;

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


function ChildClick()
{
    IsChildWindow=true;
    //Do ur work here    
}
ratnesh
quelle
3
Ich denke, Sie haben einen Fehler in Zeile "IsChildWindow == false;" gemacht. - sollte es nicht "IsChildWindow = false;" sein?
Andre Schweighofer
-5
<a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>
andres descalzo
quelle
5
Dies verhindert auch, dass der Link navigiert.
Rex M
Ja oder nicht was benötigt wird. Oder müssen Sie nevegar sein?
andres descalzo