2 votes

event.preventDefault() n'annule pas la direction du lien dans jQuery Mobile

Contexte
Je me suis débattu avec ce petit problème stupide qui consiste à essayer d'annuler la direction du lien lorsque l'événement click est déclenché sur un élément d'ancrage dans l'application jQuery Mobile.

Disons que j'ai un document simple de plusieurs pages comme celui-ci :

<div data-role="page" id="page-1">          
    <div data-role="content">
        <a href="#page-2" id="mLink">page 2</a>
    </div><!-- /content -->
</div><!-- /page -->

<div data-role="page" id="page-2">
    <div data-role="content">
    </div><!-- /content -->
</div><!-- /page -->

... et JavaScript comme ceci :

(function (MyApp, $, undefined) {
    'use strict';

    // Initializes app
    function init() {       
        $('#mLink').on('click', function (event) {
            event.preventDefault();
            //event.stopPropagation();
            //event.stopImmediatePropagation();

        });
    }

    // jQuery Mobile is ready now -> override defaults
    $(document).on("mobileinit", function () {
        // Set the default page transition
        $.mobile.defaultPageTransition  = 'slide';
    });

    // jQuery Mobile is ready now 
    $(document).ready(init);

}(window.MyApp = window.MyApp || {}, jQuery));

Problème
Je n'arrive pas à comprendre pourquoi event.preventDefault() n'annule pas la transition de page. Cependant, si j'ajoute event.stopPropagation() il l'annulera. De même, si je supprime la bibliothèque jQuery Mobile de l'application, celle-ci fonctionne sans event.stopPropagation() .

Question
Ce comportement est-il normal et est-il correct de toujours les appeler tous les deux dans le gestionnaire pour annuler la direction du lien ?

Notas
J'utilise jQuery Mobile uniquement pour ses fonctions de modèle multipage, de navigation et de transition.

Question supplémentaire
La question qui se cachait derrière ma question initiale était en quelque sorte ce que fait jQuery Mobile à un lien qui intercepte la méthode event.preventDefault() pour pas empêcher l'action par défaut du lien, c'est-à-dire aller à la page cible ".

6voto

Jonathan Wilson Points 1439

Normal ? Oui. On peut appeler les deux ? Oui.
event.preventDefault() est le seul outil dont vous disposez pour empêcher le comportement par défaut du navigateur et event.stopPropagation() est le seul outil dont vous disposez pour empêcher l'exécution de gestionnaires d'événements concurrents.

Si vous voulez une seule ligne, vous pouvez utiliser return false pour obtenir le même résultat. De http://api.jquery.com/on/ :

Le fait de retourner false à partir d'un gestionnaire d'événement appellera automatiquement event.stopPropagation() et event.preventDefault(). Une valeur false peut également être passée pour le comme raccourci de function(){ return false ; }. Ainsi , $("a.disabled").on("click", false) ; attache un gestionnaire d'événements à tous les liens de la classe "disabled" qui les empêche d'être suivis. lorsqu'ils sont cliqués et empêche également l'événement d'apparaître sous forme de bulles.

3voto

Elias Van Ootegem Points 29404

Je dois admettre que je ne suis pas trop familier avec jQuery mobile, mais je ne suis pas du tout surpris par cela. J'ai récemment écrit quelques script pour les appareils mobiles (JS pur) et la première chose que l'on remarque est l'absence totale d'événement de clic sur la plupart d'entre eux. Tout est touchez maintenant.

Le fait est que les événements tactiles sont fortement surchargé Il n'y a pas d'action par défaut à prendre sur l'écran : lorsque l'utilisateur touche l'écran et le maintient pendant un temps X, il peut essayer de sélectionner du texte, d'obtenir une loupe, ou ce toucher initial peut être le début d'un glissement. Il n'y a pas vraiment d'action par défaut à prendre sur touchstart . La plupart des scripts qui vous offrent une tab il suffit d'ajouter un écouteur pour un événement touchstart qui lie un touchend à l'élément touché pour Xms, et le mapper à un fichier click .

Empêcher l'action par défaut n'arrête pas l'événement en tant que tel, son action par défaut (s'il y en a une) ne passe pas, mais l'événement se propage tout de même dans le DOM, le touchend listener est activé et ce handler sera celui qui déclenchera tout. Si vous ne deviez pas empêcher l'action par défaut, mais simplement empêcher l'événement de se propager plus loin dans le DOM, vers sa cible, je pense que le gestionnaire touchout n'est jamais lié, ou du moins n'est jamais déclenché. En d'autres termes, en ce qui concerne l'élément, l'élément touchstart ne l'a jamais atteint, il ne s'est donc jamais produit si un événement touchend est tiré sans un touchstart cela doit signifier que le toucher a commencé ailleurs dans le DOM.

Cela explique, je pense, pourquoi vous obtenez ce comportement légèrement inattendu. Maintenant, vos questions :

Sans le mobile jQuery, le gestionnaire de clic est appelé. Je sais que je viens de dire qu'il n'y a pas de véritable événement de clic sur les appareils tactiles, mais les liens déclenchent des gestionnaires de clics qui sont directement liés aux éléments. Cependant, l'événement de clic ne peut pas vraiment être délégué sur les appareils mobiles, seule la liaison directe semble faire l'affaire. Vous pourriez peut-être les attraper dans leur phase de bulle, mais pour les ancres, cela limite un peu trop vos options. Dans votre extrait, vous liez un gestionnaire de clics directement à votre élément, ce qui pourrait expliquer pourquoi cela fonctionne avec le jQ ordinaire et non avec le jQm.

Un comportement normal ? Oui, je le crois. D'après mon expérience, il l'est. Est-il possible d'appeler les deux méthodes pour arrêter l'événement ? Bien sûr, tant que vous connaissez la différence entre les deux et que vous savez quand et pourquoi vous n'appelez qu'une seule méthode. tuer l'événement, je ne vois aucun mal à appeler les deux.

Note : Les deux réponses déjà données disent que return false; revient au même que d'appeler les deux stopPropagation y preventDefault . Bien que cela soit vrai dans jQuery, c'est PAS le cas lorsque vous vous retrouvez à écrire du JS pur. En JavaScript pur, renvoyer false depuis votre gestionnaire revient à appeler seulement preventDefault alors faites attention.
Pour une fois, la mise en œuvre de JScript de MS en est un bon exemple :

//w3c:
e.preventDefault();
e.stopPropagation();
//IE:
e.returnValue = false;
e.cancelBubble = true;

le gestionnaire retourne false === l'objet événement a une valeur de retour de false mais sa capacité à faire des bulles reste inchangée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X