jQuery Mobile: document prêt vs. page Événements

J'utilise jQuery Mobile, et j'ai du mal à comprendre les différences entre les événements classic document ready et jQuery Mobile page.

  1. Quelle est la vraie différence?

    Pourquoi devrait

    <!-- language: lang-js -->
    
    $(document).ready() {
    
    });
    

    Être mieux que

    $(document).on('pageinit') {
    
    });
    
  2. Quel est l'ordre des événements de page, lorsque vous passez d'une page à l'autre?

  3. Comment puis-je envoyer des données d'une page à une autre et est-il possible d'accéder aux données de la précédente la page?

251
demandé sur Peter Mortensen 2013-01-23 01:50:56

5 réponses

JQuery Mobile 1.4 Mise À Jour:

Mon article original était destiné à l'ancienne façon de gérer les pages, essentiellement tout avant jquery mobile 1.4. Ancienne façon de gérer est maintenant obsolète et il restera actif jusqu'à (y compris) jquery mobile 1.5, de sorte que vous pouvez toujours utiliser tout ce qui est mentionné ci-dessous, au moins jusqu'à l'année prochaine et jquery mobile 1.6.

Les anciens événements, y compris pageinit n'existent plus, ils sont remplacés par pagecontainer widget. Pageinit est complètement effacé et vous pouvez utiliser pagecreate à la place, cet événement est resté le même et ne va pas être modifié.

Si vous êtes intéressé par une nouvelle façon de gérer les événements de page, jetez un oeil tiens, dans tous les autres cas, n'hésitez pas à continuer avec cet article. Vous devriez lire cette réponse même si vous utilisez jQuery mobile 1.4 +, cela va au-delà des événements de page, donc vous trouverez probablement beaucoup d'informations utiles.

Plus vieux contenu:

Cet article peut également être trouvé comme une partie de mon blog ICI.

$(document).on('pageinit') vs $(document).ready()

La première chose que vous apprenez dans jQuery est d'appeler du code à l'intérieur du $(document).ready() fonction afin que tout s'exécute dès que le DOM est chargé. Cependant, dans jQuery Mobile, Ajax est utilisé pour charger le contenu de chaque page dans le DOM pendant que vous naviguez. Pour cette raison$(document).ready() déclenchera avant votre première page est chargé et chaque code destiné à la manipulation de la page sera exécuté après une actualisation de la page. Cela peut être un bug très subtil. Sur certains systèmes, il peut sembler que cela fonctionne bien, mais sur d'autres, cela peut provoquer une bizarrerie erratique et difficile à répéter.

Syntaxe jQuery Classique:

$(document).ready(function() {

});

Pour résoudre ce problème (et croyez-moi, c'est un problème) jQuery Mobile les développeurs ont créé des événements de page. En bref page sont des événements déclenchés en un point particulier de la page exécution. L'un de ces événements de page est un pageinit événement et nous pouvons l'utiliser comme ceci:

$(document).on('pageinit', function() {

});

Nous pouvons aller encore plus loin et utiliser un id de page au lieu du sélecteur de document. Disons que nous avons la page mobile jQuery avec un id index :

<div data-role="page" id="index">
    <div data-theme="a" data-role="header">
        <h3>
            First Page
        </h3>
        <a href="#second" class="ui-btn-right">Next</a>
    </div>

    <div data-role="content">
        <a href="#" data-role="button" id="test-button">Test button</a>
    </div>

    <div data-theme="a" data-role="footer" data-position="fixed">

    </div>
</div>

Pour exécuter du code qui ne sera disponible que pour la page d'index, nous pourrions utiliser cette syntaxe:

$('#index').on('pageinit', function() {

});

Pageinit l'événement sera exécuté chaque fois que la page sera chargée et affichée pour la première fois. Il ne se déclenchera pas à nouveau sauf si la page est actualisée manuellement ou si le chargement de la page Ajax est désactivé. Dans le cas où vous voulez que le code s'exécute chaque fois que vous visitez une page, il est préférable d'utiliser pagebeforeshow event.

Voici un exemple de travail: http://jsfiddle.net/Gajotres/Q3Usv / pour démontrer ce problème.

Quelques notes supplémentaires sur cette question. Peu importe si vous utilisez 1 html plusieurs pages ou plusieurs fichiers HTML paradigme il est conseillé de séparer tous vos personnalisés Gestion de page JavaScript dans un seul fichier JavaScript séparé. Cela notera améliorer votre code, mais vous aurez une bien meilleure vue d'ensemble du code, en particulier lors de la création d'une application jQuery Mobile.

Il y a aussi un autre événement spécial jQuery Mobile et il s'appelle mobileinit . Lorsque jQuery Mobile démarre, il déclenche une mobileinit événement sur l'objet document. Pour remplacer les paramètres par défaut, liez-les à mobileinit. L'un des bons exemples d'utilisation de mobileinit consiste à désactiver le chargement de la page Ajax ou à modifier le comportement du chargeur Ajax par défaut.

$(document).on("mobileinit", function(){
  //apply overrides here
});

Ordre de transition des événements de la Page

Premier de tous les événements peuvent être trouvés ici: http://api.jquerymobile.com/category/events/

Disons que nous avons une page A et une page B, c'est un ordre de déchargement/chargement:

  1. Page B - événement pagebeforecreate

  2. Page B - événement pagecreate

  3. Page B - événement pageinit

  4. Page A - événement pagebeforehide

  5. Page A - événement pageremove

  6. Page a-événement masquer la page

  7. Page B - événement pagebeforeshow

  8. Page B - événement pageshow

Pour une meilleure compréhension des événements de la page, Lisez ceci:

  • pagebeforeload, pageload et pageloadfailed sont déclenchés lorsqu'une page est chargée
  • pagebeforechange, pagechange et pagechangefailed sont page modifier les événements. Ces événements sont déclenchés lorsqu'un utilisateur navigue entre les pages application.
  • pagebeforeshow, pagebeforehide, pageshow et pagehide sont page événements de transition. Ces événements sont déclenchés avant, pendant et après la transition et sont nommés.
  • pagebeforecreate, pagecreate et pageinit sont pour la page d'initialisation.
  • pageremove peut être déclenché puis géré lorsqu'une page est supprimée du DOM

Exemple de chargement de la Page jsFiddle: http://jsfiddle.net/Gajotres/QGnft/

Si AJAX N'est pas activé, certains événements peuvent ne pas se déclencher.

Empêcher la transition de page

Si, pour une raison quelconque, la transition de page doit être empêchée à certaines conditions, cela peut être fait avec ce code:

$(document).on('pagebeforechange', function(e, data){
    var to = data.toPage,
        from = data.options.fromPage;

    if (typeof to  === 'string') {
        var u = $.mobile.path.parseUrl(to);
        to = u.hash || '#' + u.pathname.substring(1);
        if (from) from = '#' + from.attr('id');

        if (from === '#index' && to === '#second') {
            alert('Can not transition from #index to #second!');
            e.preventDefault();
            e.stopPropagation();

            // remove active status on a button, if transition was triggered with a button
            $.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active ui-focus ui-btn');;
        }
    }
});

Cet exemple fonctionnera dans tous les cas car il déclenchera une mendicité de chaque transition de page et ce qui est le plus important, il empêchera le changement de page avant que la transition de page ne puisse produire.

Voici un exemple de travail:

Empêcher la liaison/le déclenchement d'événements multiples

jQuery Mobile Fonctionne d'une manière différente des applications Web classiques. Selon la façon dont vous avez réussi à lier vos événements chaque fois que vous visitez une page, il liera les événements encore et encore. Ce n'est pas une erreur, c'est simplement comment jQuery Mobile gère ses pages. Par exemple, jetez un oeil à cet extrait de code:

$(document).on('pagebeforeshow','#index' ,function(e,data){
    $(document).on('click', '#test-button',function(e) {
        alert('Button click');
    });
});

Exemple de travail jsFiddle: http://jsfiddle.net/Gajotres/CCfL4/

Chaque fois que vous visitez la page #index cliquez sur événement va être lié à la touche #test-bouton. Testez - le en passant de la page 1 à la page 2 et en arrière plusieurs fois. Il y a peu de façons d'éviter ce problème:

Solution 1

Meilleure solution serait d'utiliser pageinit pour lier les événements. Si vous jetez un oeil à la documentation officielle, vous trouverez que pageinit déclenchera SEULEMENT une fois, tout comme document prêt, il n'y a donc aucun moyen que les événements soient liés à nouveau. C'est la meilleure solution parce que vous n'avez pas de surcharge de traitement comme lors de la suppression d'événements avec méthode.

Exemple de travail jsFiddle: http://jsfiddle.net/Gajotres/AAFH8/

Cette solution de travail est faite sur la base d'un exemple problématique précédent.

Solution 2

Supprimer l'événement avant de le lier:

$(document).on('pagebeforeshow', '#index', function(){
    $(document).off('click', '#test-button').on('click', '#test-button',function(e) {
        alert('Button click');
    });
});

Exemple de travail jsFiddle: http://jsfiddle.net/Gajotres/K8YmG/

Solution 3

Utilisez un sélecteur de filtre jQuery, comme ceci:

$('#carousel div:Event(!click)').each(function(){
    //If click is not bind to #carousel div do something
});

Parce que le filtre d'événement ne fait pas partie du framework jQuery officiel, il peut être trouvé ici: http://www.codenothing.com/archives/2009/event-filter/

En un mot, si la vitesse est votre principale préoccupation alors La Solution 2 est bien meilleure que la Solution 1.

Solution 4

Un nouveau, probablement le plus facile d'entre eux tout.

$(document).on('pagebeforeshow', '#index', function(){
    $(document).on('click', '#test-button',function(e) {
        if(e.handled !== true) // This will prevent event triggering more than once
        {
            alert('Clicked');
            e.handled = true;
        }
    });
});

Exemple de travail jsFiddle: http://jsfiddle.net/Gajotres/Yerv9/

Tnx à la sholsinger pour cette solution: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/

PageChange événement bizarreries-déclenchement deux fois

Parfois, l'événement pagechange peut se déclencher deux fois et cela n'a rien à voir avec le problème mentionné précédemment.

La raison l'événement pagebeforechange se produit deux fois est dû à l'appel récursif dans changePage lorsque toPage n'est pas un objet DOM amélioré jQuery. Cette récursivité est dangereuse, car le développeur est autorisé à modifier le toPage dans l'événement. Si le développeur définit systématiquement toPage sur une chaîne, dans le gestionnaire d'événements pagebeforechange, qu'il s'agisse ou non d'un objet, une boucle récursive infinie résultera. L'événement pageload passe la nouvelle page en tant que propriété page de l'objet de données (Ceci devrait être ajouté à la documentation, il n'est pas répertorié actuellement). L'événement pageload pourrait donc être utilisé pour accéder à la page chargée.

En quelques mots, cela se produit parce que vous envoyez des paramètres supplémentaires via pageChange.

Exemple:

<a data-role="button" data-icon="arrow-r" data-iconpos="right" href="#care-plan-view?id=9e273f31-2672-47fd-9baa-6c35f093a800&amp;name=Sat"><h3>Sat</h3></a>

Pour résoudre ce problème, utilisez n'importe quel événement de page répertorié dans ordre de transition des événements de Page.

Heures De Changement De Page

Comme mentionné, lorsque vous passez d'une page mobile jQuery à une autre, généralement, soit en cliquant sur un lien vers une autre page mobile jQuery qui existe déjà dans le DOM, soit en appelant manuellement $.mobile.changePage, plusieurs événements et actions ultérieures se produisent. À un niveau élevé, les actions suivantes se produisent:

  • un processus de changement de page est lancé
  • Une nouvelle page est chargée
  • Le contenu de cette page est "amélioré" (style)
  • une transition (slide / pop/etc) de la page existante vers la nouvelle page se produit

Ceci est un benchmark de transition de page moyenne:

Chargement et traitement de la Page: 3 ms

Améliorer la Page: 45 ms

Transition: 604 ms

Durée Totale: 670 ms

*Ces valeurs sont en millisecondes.

Comme vous pouvez le voir, un événement de transition consomme près de 90% du temps d'exécution.

Manipulation des Données/Paramètres entre les transitions de page

C'est possible pour envoyer un paramètre / s d'une page à l'autre pendant la transition de page. Cela peut être fait de quelques façons.

Référence: https://stackoverflow.com/a/13932240/1848600

Solution 1:

Vous pouvez passer des valeurs avec changePage:

$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });

Et lisez-les comme ce:

$(document).on('pagebeforeshow', "#index", function (event, data) {
    var parameters = $(this).data("url").split("?")[1];;
    parameter = parameters.replace("parameter=","");
    alert(parameter);
});

Exemple:

Index.html

<!DOCTYPE html>
  <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>
    </title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
    <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
    </script>
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
    <script>
        $(document).on('pagebeforeshow', "#index",function () {
            $(document).on('click', "#changePage",function () {
                $.mobile.changePage('second.html', { dataUrl : "second.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : false, changeHash : true });
            });
        });

        $(document).on('pagebeforeshow', "#second",function () {
            var parameters = $(this).data("url").split("?")[1];;
            parameter = parameters.replace("parameter=","");
            alert(parameter);
        });
    </script>
   </head>
   <body>
    <!-- Home -->
    <div data-role="page" id="index">
        <div data-role="header">
            <h3>
                First Page
            </h3>
        </div>
        <div data-role="content">
          <a data-role="button" id="changePage">Test</a>
        </div> <!--content-->
    </div><!--page-->

  </body>
</html>

De seconde en Seconde.html

<!DOCTYPE html>
  <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>
    </title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
    <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
    </script>
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
   </head>
   <body>
    <!-- Home -->
    <div data-role="page" id="second">
        <div data-role="header">
            <h3>
                Second Page
            </h3>
        </div>
        <div data-role="content">

        </div> <!--content-->
    </div><!--page-->

  </body>
</html>

Solution 2:

Ou vous pouvez créer un objet JavaScript persistant à des fins de stockage. Tant que Ajax est utilisé pour le chargement de la page (et que la page n'est pas rechargée), cet objet restera actif.

var storeObject = {
    firstname : '',
    lastname : ''
}

Exemple: http://jsfiddle.net/Gajotres/9KKbx/

Solution 3:

, Vous pouvez également accéder aux données de la page précédente comme ceci:

$(document).on('pagebeforeshow', '#index',function (e, data) {
    alert(data.prevPage.attr('id'));
});

PrevPage objet contient une page précédente complète.

Solution 4:

Comme dernière solution, nous avons une implémentation HTML astucieuse de localStorage. Il ne fonctionne qu'avec les navigateurs HTML5 (y compris les navigateurs Android et iOS) mais toutes les données stockées sont persistantes via la page rafraîchir.

if(typeof(Storage)!=="undefined") {
    localStorage.firstname="Dragan";
    localStorage.lastname="Gaic";
}

Exemple: http://jsfiddle.net/Gajotres/J9NTr/

Probablement la meilleure solution, mais elle échouera dans certaines versions d'iOS 5.X. c'est une erreur bien connue.

Ne pas Utiliser .live() / .bind() / .delegate()

J'ai oublié de mentionner (et tnx andleer pour me rappeler) utiliser on / off pour la liaison/déliement des événements, live/die et bind/délier sont obsolètes.

Le .la méthode live() de jQuery a été considérée comme une aubaine quand elle a été introduite à L'API dans la version 1.3. Dans une application jQuery typique, il peut y avoir beaucoup de manipulation DOM et il peut devenir très fastidieux de s'accrocher et de se décrocher au fur et à mesure que les éléments vont et viennent. La méthode .live() a permis d'accrocher un événement pour la durée de vie de l'application en fonction de son sélecteur. Grand droit? Faux, la méthode .live() est extrêmement lente. La méthode .live() accroche réellement ses événements à l'objet document, ce qui signifie que l'événement doit sortir de l'élément qui a généré l'événement jusqu'à ce qu'il atteigne le document. Cela peut être incroyablement fastidieux.

Il est maintenant obsolète. Les gens de l'équipe jQuery ne recommandent plus son utilisation et moi non plus. même s'il peut être fastidieux d'accrocher et de décrocher des événements, votre code sera beaucoup plus rapide sans la méthode .live() qu'avec elle.

Au Lieu de .live() vous devez utiliser .on(). .on() est d'environ 2-3x plus rapide que .live(). Jetez un oeil à cet événement binding benchmark: http://jsperf.com/jquery-live-vs-delegate-vs-on/34, tout sera clair à partir de là.

Benchmarking:

Il y a un excellent script fait pourjQuery Mobile Page Events benchmarking. Il peut être trouvé ici: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js . mais avant de faire quoi que ce soit avec elle, je vous conseille de supprimer son alert système de notification (chaque "page de changement" va vous montrer ces données en arrêtant l'application) et le changer pour console.log fonction.

Fondamentalement, ce script enregistrera tous vos événements de page et si vous lisez attentivement cet article (descriptions des événements de page), vous saurez combien de temps JQM a passé des améliorations de page, des transitions de page ....

Notes Finales

Toujours, Et je veux dire toujours lire la documentation officielle jQuery Mobile. Il vous fournira généralement les informations nécessaires, et contrairement à d'autres documents celui-ci est plutôt bon, avec suffisamment d'explications et d'exemples de code.

Changements:

  • 30.01.2013-ajout d'une nouvelle méthode de prévention de déclenchement d'événements multiples
  • 31.01.2013-ajout d'une meilleure clarification pour le chapitre manipulation des Données/Paramètres entre les transitions de page
  • 03.02.2013-ajout de nouveaux contenus / exemples au chapitre manipulation des Données/Paramètres entre les transitions de page
  • 22.05.2013 - Ajout d'une solution pour transition de page / prévention des changements et ajout de liens vers la documentation officielle de l'API page events
  • 18.05.2013-ajout d'une autre solution contre la liaison d'événements multiples
436
répondu Gajotres 2017-09-10 20:43:14

Certains d'entre vous pourraient trouver cela utile. Il suffit de copier coller dans votre page et vous obtiendrez une séquence dans laquelle les événements sont déclenchés dans la console Chromée (Ctrl + Maj + j').

$(document).on('pagebeforecreate',function(){console.log('pagebeforecreate');});
$(document).on('pagecreate',function(){console.log('pagecreate');});
$(document).on('pageinit',function(){console.log('pageinit');});
$(document).on('pagebeforehide',function(){console.log('pagebeforehide');});
$(document).on('pagebeforeshow',function(){console.log('pagebeforeshow');});
$(document).on('pageremove',function(){console.log('pageremove');});
$(document).on('pageshow',function(){console.log('pageshow');});
$(document).on('pagehide',function(){console.log('pagehide');});
$(window).load(function () {console.log("window loaded");});
$(window).unload(function () {console.log("window unloaded");});
$(function () {console.log('document ready');});

Vous n'allez pas voir unload dans la console car il est déclenché lorsque la page est déchargée (lorsque vous vous éloignez de la page). Utilisez-le comme ceci:

$(window).unload(function () { debugger; console.log("window unloaded");});

Et vous verrez ce que je veux dire.

17
répondu Matas Vaitkevicius 2017-09-10 20:49:32

C'est la bonne façon:

Pour exécuter du code qui ne sera disponible que pour la page d'index, nous pourrions utiliser cette syntaxe:

$(document).on('pageinit', "#index",  function() {
    ...
});
3
répondu kecco 2017-09-10 20:46:09

La simple différence entre document ready et page event dans jQuery-mobile est la suivante:

  1. L'événement document ready est utilisé pour toute la page HTML,

    $(document).ready(function(e) {
        // Your code
    });
    
  2. Lorsqu'il y a un événement de page, utilisez pour gérer un événement de page particulier:

    <div data-role="page" id="second">
        <div data-role="header">
            <h3>
                Page header
            </h3>
        </div>
        <div data-role="content">
            Page content
        </div> <!--content-->
        <div data-role="footer">
            Page footer
        </div> <!--footer-->
    </div><!--page-->
    

Vous pouvez également utiliser document pour gérer l'événement pageinit:

$(document).on('pageinit', "#mypage", function() {

});
1
répondu LeoMobDev 2017-09-10 20:48:22

Pendant que vous utilisez .on (), c'est essentiellement une requête en direct que vous utilisez.

D'autre part, .ready (comme dans votre cas) est une requête statique. Tout en l'utilisant, vous pouvez mettre à jour dynamiquement les données et ne pas avoir à attendre le chargement de la page. Vous pouvez simplement transmettre les valeurs dans votre base de données (si nécessaire) lorsqu'une valeur est saisie.

L'utilisation de requêtes en direct est courante dans les formulaires où nous entrons des données (compte ou messages ou même commentaires).

-1
répondu Pranjal 2017-09-10 20:50:36