¿Cómo evito que se active el evento onclick de un padre cuando se hace clic en un ancla secundaria?

347

Actualmente estoy usando jQuery para hacer clic en un div y en este div también tengo anclajes. El problema con el que me encuentro es que cuando hago clic en un ancla, ambos eventos de clic se activan (para el div y el ancla). ¿Cómo evito que se active el evento onclick del div cuando se hace clic en un ancla?

Aquí está el código roto:

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
fuente

Respuestas:

459

Los eventos aparecen en el punto más alto del DOM en el que se ha adjuntado un evento de clic. Entonces, en su ejemplo, incluso si no tuviera ningún otro elemento explícitamente seleccionable en el div, cada elemento secundario del div burbujeará su evento de clic en el DOM hasta que el controlador de eventos de clic del DIV lo detecte.

Hay dos soluciones para esto: verificar quién realmente originó el evento. jQuery pasa un objeto eventargs junto con el 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;
});

También puede adjuntar un controlador de eventos de clic a sus enlaces que les indica que dejen de burbujear eventos después de que se ejecute su propio controlador:

$("#clickable a").click(function(e) {
   // Do something
   e.stopPropagation();
});
Rex M
fuente
3
Gran respuesta. Es bueno saber que también hay opciones.
Jonathon Watney
44
+1! Adjuntar un controlador de clics con stopPropagation es un buen truco, ¡gracias!
Thomas
2
Si tenía un montón de elementos en los que deseaba evitar la propagación, podría encontrar su elemento principal y la cabeza para evitar que también burbujee allí. Entonces, en lugar de interceptar todos los enlaces a en un div, digamos, por ejemplo, simplemente intercepte el clic incluso en el div mismo y evite que suba más y estará listo.
sucitivel
21
El uso if( e.target !== this) return;en el padre es mejor que e.stopPropagation()en el niño, ya que nunca se sabe si alguien más adjunta algún controlador a los niños, o si una biblioteca debe adjuntar un controlador a un niño (y no desea meterse con el código de la biblioteca). Es una mejor separación de preocupaciones.
UTF_or_Death
3
Poner el if( e.target !== this) return;cheque en el padre significa que si se hace clic en cualquiera de los otros hijos de ese padre que no tienen sus propios controladores onClick, entonces no sucede nada. Por lo tanto, es inútil para una situación en la que tiene, por ejemplo, un div padre cliqueable. e.stopPropagation()funciona bien sin embargo.
derf26
100

Use el método stopPropagation , vea un ejemplo:

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

Como dijo jQuery Docs:

stopPropagation El método evita que el evento haga burbujear el árbol DOM, evitando que cualquier controlador principal sea notificado del evento.

Tenga en cuenta que no impide que otros oyentes manejen este evento (por ejemplo, más de un controlador de clic para un botón), si no es el efecto deseado, debe usarlo stopImmediatePropagation.

Cleiton
fuente
48

Aquí mi solución para todos los que buscan un código que no sea jQuery (javascript puro)

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

Su código no se ejecutará si se hace clic en los hijos de los padres

Sabaz
fuente
1
Esto funcionó para mí, necesitaba una solución que no sea JS / jQuery. 10x!
LA
Gran respuesta. Acabo de pasar el evento directamente. Entonces no window.eventutilicé, lo que MDN desalienta: developer.mozilla.org/en-US/docs/Web/API/Window/event . Si puede perder el tiempo, le agradecería si pudiera comentar por qué lo usó window.event(tal vez es un problema que existió en 2015 o no entendí el motivo).
RMo
15

también puedes probar esto

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

Si no tiene la intención de interactuar con el / los elemento / s interno / s en ningún caso, entonces una solución CSS puede ser útil para usted.

Simplemente configure los elementos internos a pointer-events: none

en tu caso:

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

o para apuntar a todos los elementos internos en general:

.clickable * {
    pointer-events: none;
}

Este truco fácil me ahorró mucho tiempo mientras desarrollaba con ReactJS

El soporte del navegador se puede encontrar aquí: http://caniuse.com/#feat=pointer-events

Hooman Askari
fuente
8

Si tiene varios elementos en el div en el que se puede hacer clic, debe hacer esto:

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

Usar return false;o e.stopPropogation();no permitirá que se ejecute más código. Se detendrá el flujo en este punto mismo.

Imamudin Naseem
fuente
Sí, esto es importante, me encontré con esto yo mismo. Pero la respuesta anterior de Rex es útil: puede obtener el elemento en el que se hizo clic y, en algunos casos, usar esto en la lógica que está tratando de detener. .target.nodeName también fue útil para tener una idea clara de lo que fue golpeado.
Watercayman
8

Escribir si alguien necesita (trabajó para mí):

event.stopImmediatePropagation()

De esta solución.

Bahadir Tasdemir
fuente
4

Alternativa en línea:

<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
fuente
3

Aquí hay un ejemplo usando Angular 2+

Por ejemplo, si desea cerrar un componente modal si el usuario hace clic fuera de él:

// 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
fuente
1

Debe evitar que el evento llegue (burbujee) al padre (el div). Vea la parte sobre burbujear aquí , y la información de API específica de jQuery aquí .

Matt Ball
fuente
Frio. Gracias por la información sobre el evento burbujeante.
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
fuente
0

Para especificar algún subelemento como no cliqueable, escriba la jerarquía css como en el siguiente ejemplo.

En este ejemplo, detengo la propagación a cualquier elemento (*) dentro de td dentro de tr dentro de una tabla con la clase ".subtable"

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

});
usuario3202819
fuente
0

ignoreParent () es una solución pura de JavaScript.

Funciona como una capa intermedia que compara las coordenadas del clic del mouse con las coordenadas de los elementos secundarios. Dos simples pasos de implementación:

1. Ponga el código ignoreParent () en su página.

2. En lugar del onclick original del padre = "parentEvent ();" , escribir:

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

Puede pasar identificadores de cualquier número de elementos secundarios a la función y excluir otros.

Si hizo clic en uno de los elementos secundarios, el evento principal no se activa. Si hizo clic en el elemento primario, pero no en ninguno de los elementos secundarios [proporcionados como argumentos], se activa el evento principal.

código ignoreParent () en Github

Fom
fuente
0

Si está en contexto en línea, en HTML intente esto:

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

En caso de que alguien tuviera este problema usando React, así es como lo resolví.

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

Componente render ():

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

Al agregar una función onClick para el modal hijo (div de contenido), se evita que los eventos de clic del mouse alcancen la función 'closeLogin' del elemento padre.

Esto hizo el truco para mí y pude crear un efecto modal con 2 divs simples.

Claudio
fuente
-3

agregue alo siguiente:

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

o return false;desde el controlador de clic para me #clickablegusta:

  $("#clickable").click(function() {
        var url = $("#clickable a").attr("href");
        window.location = url;
        return false;
   });
TheIdiot de la aldea
fuente
-3

Todas las soluciones son complicadas y de jscript. Aquí está la versión más simple:

var IsChildWindow=false;

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


function ChildClick()
{
    IsChildWindow=true;
    //Do ur work here    
}
ratnesh
fuente
3
Creo que cometió un error en la línea "IsChildWindow == false;" - ¿No debería ser "IsChildWindow = false;"?
Andre Schweighofer el
-5
<a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>
andres descalzo
fuente
55
Esto también evita que el enlace navegue.
Rex M
Sí, o no lo que se necesita ?. ¿O necesitas ser nevegar?
andres descalzo