web-dev-qa-db-fra.com

event.preventDefault () et return false (pas de jQuery)

Je me suis demandé si event.preventDefault() et return false Étaient les mêmes.

J'ai fait quelques tests , et il semble que

  • Si le gestionnaire d'événements est ajouté à l'aide de l'ancien modèle, par exemple

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

    Ensuite, return false Empêche les actions par défaut, comme event.preventDefault().

  • Si le gestionnaire d'événements est ajouté à l'aide de addEventListener, par exemple

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

    Ensuite, return false N'empêche pas l'action par défaut.

Est-ce que tous les navigateurs se comportent comme ça?

Existe-t-il plus de différences entre event.preventDefault() et return false?

Où puis-je trouver de la documentation (je ne pouvais pas dans MDN) sur le comportement de return false Comme event.preventDefault() dans certains cas?


Ma question ne concerne que le javascript, pas jQuery. Ne la marquez donc pas comme un doublon de event.preventDefault () vs. return false , même si les deux questions ont presque le même titre.

78
Oriol

Le Spécification d'événements de modèle d'objet de document du W3C dans 1.3.1. Interfaces d’enregistrement d’événements indique que handleEvent dans EventListener n’a aucune valeur de retour:

handleEvent Cette méthode est appelée chaque fois qu'un événement du type pour lequel l'interface EventListener a été enregistrée se produit. [...] Aucune valeur de retour

sous 1.2.4. Annulation d'événement le document indique également que

L'annulation est accomplie en appelant la méthode preventDefault de l'événement. Si un ou plusieurs EventListeners appellent preventDefault au cours d'une phase du flux d'événements, l'action par défaut sera annulée.

ce qui devrait vous décourager d’utiliser tout effet que renvoyer true/false dans un navigateur et utiliser event.preventDefault().

Mettre à jour

La spécification HTML5 spécifie en fait comment traiter une valeur de retour différente. Section 7.1.5.1 de la spécification HTML indique que

Si la valeur renvoyée est une valeur fausse booléenne WebIDL, annulez l'événement.

pour tout sauf l'événement "mouseover".

Conclusion

Je recommanderais toujours d'utiliser event.preventDefault() dans la plupart des projets, car vous serez compatible avec les anciennes spécifications et donc avec les anciens navigateurs. Si vous ne devez prendre en charge que la coupe des navigateurs Edge, renvoyer false pour annuler est acceptable.

50
Thorben Croisé

Voici quelques exemples qui pourraient aider les gens à comprendre et à mieux résoudre leurs problèmes.

TL; DR

  • utiliser onclick directement dans le balisage html ou via setAttribute('onclick'...) a ses propres pièges pour ce qui est de s'assurer que vous retournez réellement car le contenu de onclick= est encapsulé dans un onclick fonction.
  • lorsque vous utilisez onclick, vous pouvez annuler l'événement en vous assurant que la fonction onclick renvoie false ... votre fonction est encapsulée ... vous devez donc exécuter onclick="return myHandler();" ou onclick="myHandler(); return false;" ou quelque chose comme ça pour s'assurer que onclick retourne false.
  • lors de l'utilisation de addEventListener ... le renvoi de false n'a aucun effet. L'interface dans la spécification dit que le type de retour est null. Utilisez event.preventDefault () à la place.
  • Vous pouvez utiliser l'API de navigateur devtools getEventListeners pour voir à quoi ressemble votre écouteur d'événement, et vérifier si votre gestionnaire d'événement ne se comporte pas comme prévu.

Exemple

Cet exemple est spécifique à l'événement click avec un lien <a> ... mais peut être généralisé pour la plupart des types d'événements.

Nous avons une ancre (lien) avec la classe js-some-link-hook Que nous voulons ouvrir une modale et empêcher toute navigation dans les pages.

Les exemples ci-dessous ont été exécutés dans Google chrome (71) sur MacOS Mojave.

Un écueil majeur est de supposer que onclick=functionName A le même comportement que d'utiliser addEventListener

attribut 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();

Puis exécutez dans la console devtools du navigateur:

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

... et vous voyez:

function onclick(event) {
function t(n){return alert("eventHandler ran"),!1}
}

Cela ne marche pas du tout. Lorsque vous utilisez onclick=, Votre fonction de gestionnaire est encapsulée dans une autre fonction. Dans ce cas, vous pouvez voir que ma définition de fonction est incluse mais non appelée car j'ai spécifié la référence de la fonction sans l'invoquer. De plus, vous pouvez voir que même si ma fonction était invoquée et que ma fonction renvoyait false ... la fonction onclick ne renverrait pas cette valeur false ... qui est nécessaire pour "annuler" l'événement. Nous avons vraiment besoin que return myHandlerFunc(); soit intégré à la fonction onclick pour que tout fonctionne.

Maintenant que nous voyons comment cela fonctionne, nous pouvons modifier le code pour faire ce que nous voulons. Exemple impair à des fins d'illustration (n'utilisez pas ce code):

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', 'return ('+eventHandler+')();');
}
addEventListenerToElement();

Vous voyez que nous avons encapsulé notre définition de fonction eventHandler dans une chaîne. Plus précisément: une fonction à exécution automatique avec une déclaration return au début.

Encore une fois dans chrome console devtools:

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

...montre:

function onclick(event) {
return (function t(e){return alert("eventHandler ran"),!1})();
}

... alors oui, ça devrait marcher. Notre return false (!1 En raison de la minification en cours, désolé). En effet, si nous cliquons sur le lien, nous obtenons l'alerte et, si elle est ignorée, la page ne navigue ni ne s'actualise.

addEventListener

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

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

navigateur devtools:

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

résultat:

function e(n){return alert("eventHandler ran"),!1}

Donc, vous pouvez déjà voir la différence. Nous ne sommes pas enveloppés dans une fonction onclick. Ainsi, notre return false (return !1 En raison d'une minification) se situe au plus haut niveau ici et nous n'avons pas à nous inquiéter d'ajouter une déclaration de retour supplémentaire comme avant.

Donc, il semble que cela devrait fonctionner. En cliquant sur le lien, nous recevons l'alerte. Annulez l'alerte et la page navigue/est actualisée. C'est-à-dire que l'événement n'a PAS été annulé en renvoyant false.

Si nous recherchons la spécification (voir les ressources en bas), nous constatons que notre fonction callback/handler pour addEventListener ne prend pas en charge le type de retour. Nous pouvons retourner ce que nous voulons, mais comme cela ne fait pas partie de l'interface, cela n'a aucun effet.

Solution: utiliser event.preventDefault() au lieu de return false; ...

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

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

navigateur devtools ...

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

donne ...

function n(e){e.preventDefault(),alert("eventHandler ran")}

...comme prévu.

Test: recevez l'alerte. Rejeter l'alerte. Non la navigation de la page ou actualiser ... qui est ce que nous voulons.

Ressources

La spécification html5 ( https://www.w3.org/TR/html5/webappapis.html#events ) confond les choses car elle utilise à la fois onclick et addEventListener dans leurs exemples et ils disent ce qui suit:

L'algorithme de traitement du gestionnaire d'événements pour un gestionnaire d'événements H et un objet d'événement E est le suivant:

...

  1. Traiter la valeur de retour comme suit:

...

Si la valeur renvoyée est une valeur fausse booléenne Web IDL, annulez l'événement.

Cela semble donc impliquer que return false Annule l'événement pour addEventListener et onclick.

Mais si vous regardez leur définition liée de event-handler, Vous voyez:

Un gestionnaire d'événements a un nom, qui commence toujours par "on" et est suivi du nom de l'événement auquel il est destiné.

...

Les gestionnaires d’événements sont exposés de deux manières.

La première méthode, commune à tous les gestionnaires d’événements, consiste en un attribut IDL de gestionnaire d’événements.

La deuxième façon est comme un attribut de contenu de gestionnaire d'événement. Les gestionnaires d'événements sur les éléments HTML et certains des gestionnaires d'événements sur les objets Windows sont exposés de cette manière.

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

Il semble donc que l'annulation de l'événement par return false Ne s'applique réellement qu'aux gestionnaires d'événements onclick (ou généralement on*) Et non aux gestionnaires d'événements enregistrés via addEventListener qui a une API différente. Étant donné que l'API addEventListener n'est pas couverte par la spécification html5 et que seuls les gestionnaires d'événements on* ... il serait moins déroutant de s'y tenir dans leurs exemples et d'appeler spécifiquement la différence.

1
mattpr