event.preventDefault () frente a devolver falso (sin jQuery)

84

Me preguntaba si event.preventDefault()y return falsesería lo mismo.

He hecho algunas pruebas y parece que

  • Si el controlador de eventos se agrega usando el modelo antiguo, por ejemplo

    elem.onclick = function(){
        return false;
    };
    

    Luego, return falseevita la acción predeterminada, como event.preventDefault().

  • Si el controlador de eventos se agrega usando addEventListener, por ejemplo

    elem.addEventListener(
        'click',
        function(e){
            return false;
        },
        false
    );
    

    Entonces, return falseno evita la acción predeterminada.

¿Todos los navegadores se comportan así?

¿Hay más diferencias entre event.preventDefault()y return false?

¿Dónde puedo encontrar documentación (no pude en MDN) sobre cómo return falsecomportarse como event.preventDefault()en algunos casos?


Mi pregunta es solo sobre javascript simple, no jQuery, así que no lo marque como un duplicado de event.preventDefault () vs. return false , incluso si ambas preguntas tienen casi el mismo título.

Oriol
fuente
Duplicado de stackoverflow.com/questions/1357118/… Si lee la pregunta, notará que se trata de un problema genérico de JS, no del específico de jQuery. jQuery solo se usó para hacer que el código de ejemplo sea lo más corto / limpio posible.
RaYell
13
@RaYell No, porque jQuery se return falsecomporta diferente al de JavaScript simple. Además, la otra pregunta no tiene ninguna respuesta que explique la diferencia en JS simple (solo hay un comentario que lo explica, pero es difícil de encontrar). Entonces creo que es mejor tener dos preguntas diferentes.
Oriol

Respuestas:

55

La Especificación de eventos del modelo de objetos de documento del W3C en 1.3.1. Las interfaces de registro de eventos indican que handleEventen EventListener no tiene valor de retorno:

handleEvent Este método se llama siempre que se produce un evento del tipo para el que se registró la interfaz EventListener. [...] Sin valor de retorno

en 1.2.4. Cancelación de evento el documento también establece que

La cancelación se logra llamando al método preventDefault del evento. Si uno o más EventListeners llaman a preventDefault durante cualquier fase del flujo de eventos, la acción predeterminada se cancelará.

lo que debería disuadirlo de utilizar cualquier efecto que pueda tener la devolución de verdadero / falso en cualquier navegador y uso event.preventDefault().

Actualizar

La especificación HTML5 en realidad especifica cómo tratar un valor de retorno de manera diferente. La sección 7.1.5.1 de la especificación HTML establece que

Si el valor de retorno es un valor falso booleano de WebIDL, cancele el evento.

para todo menos el evento "mouseover".

Conclusión

Aún así, recomendaría usarlo event.preventDefault()en la mayoría de los proyectos, ya que será compatible con la especificación anterior y, por lo tanto, con los navegadores más antiguos. Solo si solo necesita admitir navegadores de vanguardia, devolver falso para cancelar está bien.

Thorben Croisé
fuente
2
Este enlace fue escrito en 2000. La especificación HTML5: w3.org/TR/html5/webappapis.html#event-handler-attributes parece que maneja los valores de retorno para muchos eventos (no el mouseover): "Si el valor de retorno es un booleano de WebIDL valor falso, luego cancele el evento "
Charles L.
Y a partir de algunas pruebas rápidas en Chrome, ambos devuelven falso y event.preventDefault () no detiene la propagación. Crédito principalmente a @Oriol: vea detener la propagación frente a lo normal
Charles L.
Este violín compara el comportamiento de stopPropagation(), preventDefault()y return false: jsfiddle.net/m1L6of9x . En los navegadores modernos, los dos últimos tienen el mismo comportamiento.
Erik Koopmans
5

Aquí hay algunos ejemplos que pueden ayudar a las personas a comprender y solucionar mejor sus problemas.

TL; DR

  • on*controladores de eventos (por ejemplo, onclickatributo en un elemento de botón): devuelve falso para cancelar el evento
  • addEventListeneres una API diferente, los valores de retorno (p false. ej. ) se ignoran: use event.preventDefault().
  • onclick="<somejs>"tiene su propia confusión potencial porque <somejs>está envuelto en el cuerpo de una función onclick.
  • Utilice la getEventListenersAPI de devtools del navegador para ver cómo se ve su detector de eventos para solucionar problemas si su controlador de eventos no se comporta como se esperaba.

Ejemplo

Este ejemplo es específico del clickevento con un <a>enlace ... pero se puede generalizar para la mayoría de los tipos de eventos.

Tenemos un ancla (enlace) con la clase js-some-link-hookque queremos abrir un modal y evitar que suceda la navegación de la página.

Los siguientes ejemplos se ejecutaron en google chrome (71) en MacOS Mojave.

Un error importante es asumir que onclick=functionNamees el mismo comportamiento que usaraddEventListener

Digamos que tenemos una etiqueta de anclaje (enlace) que queremos manejar con javascript cuando javascript está habilitado. No queremos que el navegador siga el enlace cuando se hace clic en él (comportamiento "evitar predeterminado").

<a href="https://www.example.com/url/to/go/to/when/no/javascript"
   class="js-some-link-hook">click me!</a>

atributo onclick

function eventHandler (event) {
    // want to prevent link navigation
    alert('eventHandler ran');
    return false;
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.setAttribute('onclick', eventHandler);
}
addEventListenerToElement();

Luego, ejecútelo en la consola de devtools del navegador:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

... y ves:

function onclick(event) {
function eventHandler (event) {alert('eventHandler ran'); return false;}
}

Esto no funciona en absoluto. Cuando se utiliza onclick=su función de controlador se envuelve en otra función.

Puede ver que la definición de mi función está incluida pero no se llama porque especifiqué la referencia de la función sin invocarla. es decir, que necesitamos onclick="functionName()"no onclick="functionName"para asegurarse de que functionNamese ejecuta cuando se hace clic en el elemento.

Además, puede ver que incluso si se llamó a mi función y mi función devolvió falso ... la onclickfunción no devolvería ese valor falso ... que se requiere para 'cancelar' el evento.

Para solucionar esto, podemos establecer onclickque sea lo return myHandlerFunc();que asegura que onclickdevuelve el valor de retorno (falso) de myHandlerFunc.

También puede eliminar el return false;de myHandlerFuncy cambiar el onclickpor ser, myHandlerFunc(); return false;pero esto tiene menos sentido, ya que probablemente desee mantener la lógica junta en su función de controlador.

Tenga en cuenta que cuando configura onclickcon javascript , cuando configura onclickdirectamente en html en lugar de hacerlo con javascript (como mis ejemplos), el onclickvalor del atributo es tipo cadena y todo funciona. Si está configurando onclickusando javascript, debe prestar atención al tipo. Si dice element.setAttribute('onclick', myHandlerFunc()) myHandlerFuncque se ejecutará ahora mismo y el resultado se almacenará en el atributo ... en lugar de ejecutarse en cada clic. En su lugar, debe asegurarse de que el valor del atributo esté establecido como una cadena. element.setAttribute('onclick', 'return myHandlerFunc();')

Ahora que vemos cómo funciona, podemos modificar el código para hacer lo que queramos. Ejemplo extraño con fines ilustrativos (no use este código):

function eventHandler (e) {
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(e);
    return false;
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.setAttribute('onclick', 'return ('+eventHandler+')(event);');
}
addEventListenerToElement();

Verá que hemos envuelto nuestra definición de función eventHandler en una cadena. Específicamente: una función autoejecutable con una declaración de retorno al frente.

De nuevo en la consola de Chrome devtools:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

... muestra:

function onclick(event) {
return (function eventHandler (e) {
        // want to prevent link navigation
        alert('eventHandler ran');
        console.log(e);
        return false;
    })(event);
}

... así que sí, eso debería funcionar. Efectivamente, si hacemos clic en el enlace, recibimos la alerta y, al descartar la alerta, la página no navega a ninguna parte ni se actualiza.

Una nota más sobre onclick... Si desea recibir y utilizar elevent parámetro en el momento del evento, debe tener en cuenta que se llama "evento". Puede acceder a esto dentro de su controlador usando el nombre event(disponible a través del onclickalcance de la función principal ). O puede construir su controlador para tomarlo eventcomo parámetro (mejor para pruebas) ... por ejemplo, onclick="return myEventHandler(event);"o como ve en el ejemplo anterior.

addEventListener

function eventHandler (ev) {
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(ev);
    return false;
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();

devtools del navegador:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

resultado:

function eventHandler (ev) {
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(ev);
    return false;
}

Entonces ya puedes ver la diferencia. Con addEventListenerno estamos envueltos en una onclickfunción. Nuestro manejador recibe elevent parámetro directamente (y así podemos llamarlo como queramos). También nuestro return falseestá en el "nivel superior" aquí y no tenemos que preocuparnos por agregar una declaración de retorno adicional como con onclick.

Entonces parece que debería funcionar. Al hacer clic en el enlace obtenemos la alerta. Descarte la alerta y la página navega / se actualiza. es decir, el evento NO se canceló devolviendo falso.

Si buscamos la especificación (ver recursos en la parte inferior), vemos que nuestra función de devolución de llamada / controlador para addEventListener no admite un tipo de retorno. Podemos devolver lo que queramos, pero como no forma parte de la API / interfaz del navegador, no tiene ningún efecto.

Solución: usar en event.preventDefault()lugar de return false;...

function eventHandler (ev) {
    // want to prevent link navigation
    ev.preventDefault();
    alert('eventHandler ran');
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();

devtools del navegador ...

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

da...

function eventHandler (ev) {
    // want to prevent link navigation
    ev.preventDefault();
    alert('eventHandler ran');
}

...como se esperaba.

Probando de nuevo:

  • Haga clic en el enlace.
  • Recibe la alerta.
  • Descartar alerta.
  • No se realiza ninguna navegación o actualización de la página ... que es lo que queremos.

Entonces, addEventListenerusar event.preventDefault()como devolver falso no hace nada.

Recursos

La especificación html5 ( https://www.w3.org/TR/html5/webappapis.html#events ) confunde las cosas porque usan ambos onclicky addEventListeneren sus ejemplos y dicen lo siguiente:

El algoritmo de procesamiento del controlador de eventos para un controlador de eventos H y un objeto de evento E es el siguiente:

...

  1. Procese el valor de retorno de la siguiente manera:

...

Si el valor de retorno es un valor falso booleano de Web IDL, cancele el evento.

Entonces parece implicar que return falsecancela el evento para ambos addEventListenery onclick.

Pero, si miras su definición vinculada event-handler, ves:

Un controlador de eventos tiene un nombre, que siempre comienza con "on" y va seguido del nombre del evento al que está destinado.

...

Los controladores de eventos se exponen de dos formas.

La primera forma, común a todos los controladores de eventos, es como un atributo IDL del controlador de eventos.

La segunda forma es como un atributo de contenido del controlador de eventos. Los controladores de eventos en elementos HTML y algunos de los controladores de eventos en objetos de ventana se exponen de esta manera.

https://www.w3.org/TR/html5/webappapis.html#event-handler

Por lo tanto, parece que la return falsecancelación del evento solo se aplica a los controladores de eventos onclick(o en general on*) y no a los controladores de eventos registrados a través de los addEventListenercuales tiene una API diferente.

Dado que la addEventListenerAPI no está cubierta por la especificación html5 (solo los on*controladores de eventos) ... sería menos confuso si se apegaran a los on*controladores de eventos de estilo en sus ejemplos.

Mattpr
fuente
-2

Diferencia entre preventDefault, stopPropogation, return false

Tabla que muestra la diferencia

Acción predeterminada: acción del lado del servidor cuando se genera un evento de control.

Supongamos que tenemos el control div y dentro de él tenemos un botón. Entonces div es el control principal del botón. Tenemos el evento de clic del lado del cliente y el clic del lado del servidor del botón. También tenemos el evento de clic del lado del cliente del div.

Al hacer clic en el evento del botón en el lado del cliente, podemos controlar las acciones del control principal y el código del lado del servidor usando las siguientes tres formas:

  • return false- Esto permite solo el evento del lado del cliente del control. El evento del lado del servidor y el evento del lado del cliente del control principal no se disparan.

  • preventDefault()- Esto permite el evento de control del lado del cliente y su control principal. Evento del lado del servidor, es decir. La acción predeterminada del control no se dispara.

  • stopPropogation()- Esto permite eventos del lado del cliente así como del lado del servidor del control. El evento del lado del cliente del control no está permitido.

Rahul Shinde
fuente
21
Está equivocado, return falseno detiene la propagación, por lo que el control parental se activa ( demostración ). Además, no estoy seguro de a qué te refieres con " evento de clic del lado del servidor ".
Oriol
6
@Principiantes, ignoren esta respuesta.
Pilau
4
¿Qué es esta tontería sobre los eventos del lado del servidor? -1
Mark Amery
Creo que las cosas del lado del servidor están pensando en ASP, donde se pueden controlar los eventos en el servidor.
Andrew
5
No hay "lado del servidor" cuando se habla de JavaScript y eventos.
rawpower
-12

return falsees solo para IE, event.preventDefault()es compatible con Chrome, ff ... navegadores modernos

ppy
fuente
9
Pero en Firefox return falsefunciona como event.preventDefault()cuando se agrega el controlador de eventos con el modelo anterior
Oriol