¿Cuál es la diferencia entre event.stopPropagation y event.preventDefault?

835

Parecen estar haciendo lo mismo ...
¿Es uno moderno y otro antiguo? ¿O son compatibles con diferentes navegadores?

Cuando manejo eventos por mí mismo (sin marco), siempre verifico ambos y ejecuto ambos si están presentes. (Yo también return false, pero tengo la sensación de que no funciona con eventos adjuntos node.addEventListener).

Entonces, ¿por qué ambos? ¿Debo seguir buscando ambos? ¿O hay realmente una diferencia?

(Lo sé, muchas preguntas, pero son todas iguales =))

Rudie
fuente

Respuestas:

1016

stopPropagation evita que el evento burbujee en la cadena de eventos.

preventDefault evita la acción predeterminada que realiza el navegador en ese evento.

Ejemplos

preventDefault

$("#but").click(function (event) {
  event.preventDefault()
})
$("#foo").click(function () {
  alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

stopPropagation

$("#but").click(function (event) {
  event.stopPropagation()
})
$("#foo").click(function () {
  alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

Con stopPropagation, solo se llama al buttoncontrolador de clics mientras que el divcontrolador de clics nunca se activa.

Donde, como si lo usa preventDefault, solo se detiene la acción predeterminada del navegador, pero el controlador de clics del div aún se activa.

A continuación se presentan algunos documentos sobre las propiedades y métodos de eventos DOM de MDN:

Para IE9 y FF puede usar preventDefault & stopPropagation.

Para admitir IE8 y versiones inferiores, reemplace stopPropagationcon cancelBubbley reemplace preventDefaultconreturnValue

Raynos
fuente
¿Entonces son muy diferentes? ¿IE tiene dos métodos de evento diferentes para eso también? (¿Podrían ser iguales?) Es extraño que los frameworks cumplan ambas event.stopfunciones ... También es raro que nunca haya tenido problemas con eso. Yo uso mucho burbujear. Gracias por el ejemplo!
Rudie
@Rudie comentó sobre el soporte del navegador.
Raynos
77
Vale la pena señalar (en caso de que no mire los documentos de MSDN) que cancelBubbley returnValueson ambas propiedades (por lo tanto, debe establecerse cancelBubble = true;), y eso preventDefaulty stopPropagationson métodos (por lo que debería llamarse preventDefault();)
freefaller
1
@Raynos, solo una nota: event.stopPropagation () no solo evita que el evento burbujee en la cadena de eventos, sino que también detiene la propagación del evento en la fase de captura ( developer.mozilla.org/en-US/docs/Web/ API / Event / stopPropagation )
Yuci
1
Sería útil saber cuál es la acción predeterminada para hacer clic en un botón, de modo que pueda razonar por qué stopDefault()no funciona de la misma manera stopPropagation(). Si la acción predeterminada no llama al onclickmétodo, ¿qué es?
d512
249

Terminología

De quirksmode.org :

Captura de eventos

Cuando usa la captura de eventos

               El | El |
--------------- | | -----------------
El | elemento1 | El | El |
El | ----------- | | ----------- |
El | | element2 \ / | El |
El | ------------------------- |
El | Evento CAPTURING |
-----------------------------------

el controlador de eventos de element1 se dispara primero, el controlador de eventos de element2 se dispara por último.

Evento burbujeante

Cuando usa burbujeo de eventos

               / \
--------------- | | -----------------
El | elemento1 | El | El |
El | ----------- | | ----------- |
El | | element2 | El | El | El |
El | ------------------------- |
El | Evento BUBBLING |
-----------------------------------

el controlador de eventos de element2 se dispara primero, el controlador de eventos de element1 se dispara por último.

Cualquier evento que tenga lugar en el modelo de evento W3C se captura primero hasta que alcanza el elemento objetivo y luego vuelve a aparecer .

                 El | El | / \
----------------- | | - | | -----------------
El | elemento1 | El | El | El | El |
El | ------------- | | - | | ----------- |
El | | element2 \ / | El | El | El |
El | -------------------------------- |
El | Modelo de evento W3C |
------------------------------------------

Interfaz

Desde w3.org , para la captura de eventos :

Si la captura EventListenerdesea evitar que se produzca un mayor procesamiento del evento, puede llamar al stopPropagationmétodo de la Eventinterfaz. Esto evitará un envío adicional del evento, aunque los EventListenersregistros adicionales en el mismo nivel de jerarquía seguirán recibiendo el evento. Una vez que stopPropagation se ha llamado al método de un evento , las llamadas adicionales a ese método no tienen ningún efecto adicional. Si no existen capturadores adicionales y stopPropagationno se ha llamado, el evento activa el apropiado EventListenersen el objetivo mismo.

Para eventos burbujeantes :

Cualquier controlador de eventos puede optar por evitar una mayor propagación de eventos llamando al stopPropagationmétodo de la Eventinterfaz. Si alguno EventListenerllama a este método, se activarán todos los adicionales EventListenersen la corriente EventTargetpero el burbujeo cesará en ese nivel. Solo se requiere una llamada a stopPropagationpara evitar más burbujeos.

Para cancelación de eventos :

La cancelación se logra llamando al método Event's preventDefault. Si una o más EventListenersllamadas preventDefaultdurante cualquier fase del flujo de eventos, la acción predeterminada se cancelará.

Ejemplos

En los siguientes ejemplos, un clic en el hipervínculo en el navegador web activa el flujo del evento (se ejecutan los oyentes del evento) y la acción predeterminada del objetivo del evento (se abre una nueva pestaña).

HTML:

<div id="a">
  <a id="b" href="http://www.google.com/" target="_blank">Google</a>
</div>
<p id="c"></p>

JavaScript:

var el = document.getElementById("c");

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
}

function capturingOnClick2(ev) {
    el.innerHTML += "A event capture<br>";
}

function bubblingOnClick1(ev) {
    el.innerHTML += "DIV event bubbling<br>";
}

function bubblingOnClick2(ev) {
    el.innerHTML += "A event bubbling<br>";
}

// The 3rd parameter useCapture makes the event listener capturing (false by default)
document.getElementById("a").addEventListener("click", capturingOnClick1, true);
document.getElementById("b").addEventListener("click", capturingOnClick2, true);
document.getElementById("a").addEventListener("click", bubblingOnClick1, false);
document.getElementById("b").addEventListener("click", bubblingOnClick2, false);

Ejemplo 1 : da como resultado la salida

DIV event capture
A event capture
A event bubbling
DIV event bubbling

Ejemplo 2 : agregar stopPropagation()a la función

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
    ev.stopPropagation();
}

resultados en la salida

DIV event capture

El oyente del evento evitó una mayor propagación hacia abajo y hacia arriba del evento. Sin embargo, no impidió la acción predeterminada (una nueva pestaña de apertura).

Ejemplo 3 : agregar stopPropagation()a la función

function capturingOnClick2(ev) {
    el.innerHTML += "A event capture<br>";
    ev.stopPropagation();
}

o la función

function bubblingOnClick2(ev) {
    el.innerHTML += "A event bubbling<br>";
    ev.stopPropagation();
}

resultados en la salida

DIV event capture
A event capture
A event bubbling

Esto se debe a que ambos oyentes de eventos están registrados en el mismo objetivo de evento. Los oyentes del evento impidieron una mayor propagación ascendente del evento. Sin embargo, no impidieron la acción predeterminada (una nueva pestaña de apertura).

Ejemplo 4 : agregar preventDefault()a cualquier función, por ejemplo

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
    ev.preventDefault();
}

evita que se abra una nueva pestaña.

Ashkan
fuente
23
Gracias por la distinción más profunda entre capturar y burbujear, mientras que la otra respuesta solo aborda las preocupaciones de jQuery.
floribon
@floribon dice que no tiene intención de ofender a raynos por su respuesta.
Mahi
3
@Mahi qué? Solo digo hechos, la respuesta aceptada está usando jQuery, lo cual no es asumido por OP, por lo que para mí no es la respuesta real. Ahora eso es solo un hecho técnico, nada personal y nadie a quien ofender.
floribon el
2
Su respuesta es muy sistemática y demuestra muy bien lo que está sucediendo. Inicialmente no quería molestarte y hacer algunos cambios en tu respuesta, porque creo que podría mejorarse un poco para mayor claridad. Esta respuesta explica el modelo de evento a los principiantes y, como tal, creo que cada ayuda que podemos brindar a los principiantes es muy útil. Mi sugerencia de edición ha sido rechazada por argumentos genéricos, con los que no estoy de acuerdo. Si usted, @Ashkan, siente que estos pequeños cambios podrían ayudar a mejorar la respuesta, incorpórelos.
mucaho
68

falso retorno;


return false; hace 3 cosas separadas cuando lo llamas:

  1. event.preventDefault() - Detiene el comportamiento predeterminado de los navegadores.
  2. event.stopPropagation() - Evita que el evento propague (o "burbujee") el DOM.
  3. Detiene la ejecución de devolución de llamada y vuelve inmediatamente cuando se llama.

Tenga en cuenta que este comportamiento difiere de los controladores de eventos normales (no jQuery), en los que, en particular, return falseno impide que el evento brote.

preventDefault ();


preventDefault(); hace una cosa: detiene el comportamiento predeterminado de los navegadores.

¿Cuándo usarlos?


Sabemos lo que hacen, pero ¿cuándo usarlos? Simplemente depende de lo que quieras lograr. Úselo preventDefault();si desea "simplemente" evitar el comportamiento predeterminado del navegador. Use return false; cuando desee evitar el comportamiento predeterminado del navegador y evitar que el evento propague el DOM. En la mayoría de las situaciones en las que usaría return false; lo que realmente quiere es preventDefault().

Ejemplos:


Tratemos de entender con ejemplos:

Veremos puro ejemplo de JAVASCRIPT

Ejemplo 1:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Ejecutar el código anterior, verá el hipervínculo 'Haga clic aquí para visitar stackoverflow.com' ahora si hace clic en ese enlace primero obtendrá la alerta Javascript Enlace Seguido siguiente obtendrá la alerta Javascript div Clicked e inmediatamente se le redirige a stackoverflow.com.

Ejemplo 2

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.preventDefault();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Ejecutar el código anterior, verá el hipervínculo 'Haga clic aquí para visitar stackoverflow.com' ahora si hace clic en ese enlace primero obtendrá la alerta Javascript Enlace Seguido siguiente obtendrá la alerta Javascript div Seguido A continuación verá el hipervínculo ' Haga clic aquí para visitar stackoverflow.com 'reemplazado por el texto' Haga clic en evento evitado 'y no será redirigido a stackoverflow.com. Esto se debe al método event.preventDefault () que utilizamos para evitar que se active la acción de clic predeterminada.

Ejemplo 3

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.stopPropagation();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Esta vez, si hace clic en Enlace, no se llamará a la función executeParent () y esta vez no obtendrá el div de alerta de JavaScript . Esto se debe a que hemos evitado la propagación al div principal mediante el método event.stopPropagation (). A continuación, verá el hipervínculo 'Haga clic aquí para visitar stackoverflow.com' reemplazado por el texto 'El evento Click se ejecutará' e inmediatamente será redirigido a stackoverflow.com. Esto se debe a que no hemos evitado que la acción de clic predeterminada se active esta vez utilizando el método event.preventDefault ().

Ejemplo 4

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.preventDefault();
    event.stopPropagation();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('Div Clicked');
  }
</script>

Si hace clic en el enlace, no se llamará a la función executeParent () y no recibirá la alerta de JavaScript. Esto se debe a que hemos evitado la propagación al div principal mediante el método event.stopPropagation (). A continuación, verá el hipervínculo 'Haga clic aquí para visitar stackoverflow.com' reemplazado por el texto 'Haga clic en evento evitado' y no será redirigido a stackoverflow.com. Esto se debe a que hemos evitado que la acción de clic predeterminada se active esta vez utilizando el método event.preventDefault ().

Ejemplo 5:

Para return false, tengo tres ejemplos y todos parecen estar haciendo exactamente lo mismo (solo devolviendo false), pero en realidad los resultados son bastante diferentes. Esto es lo que realmente sucede en cada uno de los anteriores.

casos:

  1. Devolver false desde un controlador de eventos en línea evita que el navegador navegue a la dirección del enlace, pero no impide que el evento se propague a través del DOM.
  2. Devolver false desde un controlador de eventos jQuery evita que el navegador navegue a la dirección del enlace y evita que el evento se propague a través del DOM.
  3. Devolver falso de un controlador de eventos DOM normal no hace absolutamente nada.

Veremos los tres ejemplos.

  1. Retorno en línea falso.

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='return false'>Click here to visit stackoverflow.com</a>
</div>
<script>
  var link = document.querySelector('a');

  link.addEventListener('click', function() {
    event.currentTarget.innerHTML = 'Click event prevented using inline html'
    alert('Link Clicked');
  });


  function executeParent() {
    alert('Div Clicked');
  }
</script>

  1. Devolver falso de un controlador de eventos jQuery.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <a href='https://stackoverflow.com'>Click here to visit stackoverflow.com</a>
</div>
<script>
  $('a').click(function(event) {
    alert('Link Clicked');
    $('a').text('Click event prevented using return FALSE');
    $('a').contents().unwrap();
    return false;
  });
  $('div').click(function(event) {
    alert('Div clicked');
  });
</script>

  1. Devolver falso de un controlador de eventos DOM normal.

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
    return false
  }

  function executeParent() {
    alert('Div Clicked');
  }
</script>

Espero que estos ejemplos sean claros. Intente ejecutar todos estos ejemplos en un archivo html para ver cómo funcionan.

Keval Bhatt
fuente
1
Buenos ejemplos, pero hubiera sido aún mejor sin jQuery, porque jQuery falsifica el objeto de evento, por lo que es técnicamente diferente.
Rudie
1
@Rudie Actualicé mi respuesta y eliminé jquery, y también agregué un ejemplo para return false.
Keval Bhatt
17

Esta es la cita de aquí.

Event.preventDefault

El método preventDefault evita que un evento lleve a cabo su funcionalidad predeterminada. Por ejemplo, usaría preventDefault en un elemento A para dejar de hacer clic en ese elemento para que no salga de la página actual:

//clicking the link will *not* allow the user to leave the page 
myChildElement.onclick = function(e) { 
    e.preventDefault(); 
    console.log('brick me!'); 
};

//clicking the parent node will run the following console statement because event propagation occurs
logo.parentNode.onclick = function(e) { 
    console.log('you bricked my child!'); 
};

Si bien la funcionalidad predeterminada del elemento está bloqueada, el evento continúa burbujeando el DOM.

Event.stopPropagation

El segundo método, stopPropagation, permite que ocurra la funcionalidad predeterminada del evento pero evita que el evento se propague:

//clicking the element will allow the default action to occur but propagation will be stopped...
myChildElement.onclick = function(e) { 
    e.stopPropagation();
    console.log('prop stop! no bubbles!'); 
};

//since propagation was stopped by the child element's onClick, this message will never be seen!
myChildElement.parentNode.onclick = function(e) { 
    console.log('you will never see this message!'); 
};

stopPropagation efectivamente impide que los elementos primarios sepan sobre un evento dado en su hijo.

Si bien un método simple de detención nos permite manejar rápidamente los eventos, es importante pensar qué es exactamente lo que quieres que ocurra con el burbujeo. ¡Apuesto a que todo lo que un desarrollador realmente quiere es prevenir por defecto el 90% del tiempo! "Detener" incorrectamente un evento podría causarle numerosos problemas en el futuro; sus complementos pueden no funcionar y sus complementos de terceros podrían bloquearse. O peor aún: su código rompe otras funciones en un sitio.

VladL
fuente
2

Event.preventDefault- detiene el comportamiento predeterminado del navegador. Ahora viene lo que es el comportamiento predeterminado del navegador. Suponga que tiene una etiqueta de anclaje y que tiene un atributo href y esta etiqueta de anclaje está anidada dentro de una etiqueta div que tiene un evento de clic. El comportamiento predeterminado de la etiqueta de anclaje es cuando se hace clic en la etiqueta de anclaje por la que debe navegar, pero lo que hace event.preventDefault es detener la navegación en este caso. Pero nunca detiene el burbujeo del evento o la escalada del evento, es decir

<div class="container">
 <a href="#" class="element">Click Me!</a>
</div>

$('.container').on('click', function(e) {
 console.log('container was clicked');
});

$('.element').on('click', function(e) {
  e.preventDefault(); // Now link won't go anywhere
  console.log('element was clicked');
});

El resultado será

"se hizo clic en el elemento"

"se hizo clic en el contenedor"

Ahora event.StopPropation detiene el burbujeo del evento o la escalada del evento. Ahora con el ejemplo anterior

$('.container').on('click', function(e) {
  console.log('container was clicked');
});

$('.element').on('click', function(e) {
  e.preventDefault(); // Now link won't go anywhere
  e.stopPropagation(); // Now the event won't bubble up
 console.log('element was clicked');
});

El resultado será

"se hizo clic en el elemento"

Para obtener más información, consulte este enlace https://codeplanet.io/preventdefault-vs-stoppropagation-vs-stopimmediatepropagation/

Nayas Subramanian
fuente
1

event.preventDefault(); Detiene la acción predeterminada de un elemento.

event.stopPropagation(); Impide que el evento forme burbujas en el árbol DOM, evitando que los controladores principales sean notificados del evento.

Por ejemplo, si hay un enlace con un método de clic adjunto dentro de DIVo FORMque también tiene un método de clic adjunto, evitará que se active el método DIVo FORMclic.

Mike Clark
fuente
-3

$("#but").click(function(event){
console.log("hello");
  event.preventDefault();
 });


$("#foo").click(function(){
 alert("parent click event fired !");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

Manish Singh
fuente