webentwicklung-frage-antwort-db.com.de

jQuery Mobile: Dokument bereit vs. Seitenereignisse

Ich verwende jQuery Mobile und habe Probleme beim Verstehen von Unterschieden zwischen klassischen dokumentenfertigen und jQuery Mobile-Seitenereignissen.

  1. Was ist der wirkliche Unterschied?

    Warum sollte

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

    besser sein als

    $(document).on('pageinit') {
    
    });
    
  2. Wie ist die Reihenfolge der Seitenereignisse, wenn Sie von einer Seite zur nächsten wechseln?

  3. Wie kann ich Daten von einer Seite zu einer anderen senden und kann auf Daten von der vorherigen Seite zugegriffen werden?

260
user2001897

jQuery Mobile 1.4 Update:

Mein ursprünglicher Artikel war für die alte Art der Seitenbearbeitung gedacht, im Grunde alles vor jQuery Mobile 1.4. Die bisherige Vorgehensweise ist veraltet und bleibt bis (einschließlich) jQuery Mobile 1.5 aktiv. Sie können also bis zum nächsten Jahr und bis zu jQuery Mobile 1.6 weiterhin alle unten genannten Funktionen verwenden.

Alte Ereignisse, einschließlich pageinit , existieren nicht mehr, sie werden durch das Widget pagecontainer ersetzt. Pageinit wird vollständig gelöscht und Sie können pagecreate verwenden, stattdessen blieb dieses Ereignis gleich und wird nicht geändert.

Wenn Sie sich für eine neue Art der Behandlung von Seitenereignissen interessieren, werfen Sie einen Blick auf here. In allen anderen Fällen können Sie mit diesem Artikel fortfahren. Sie sollten diese Antwort lesen, auch wenn Sie jQuery Mobile 1.4 + verwenden. Sie geht über Seitenereignisse hinaus, sodass Sie wahrscheinlich viele nützliche Informationen finden.

Älterer Inhalt:

Dieser Artikel ist auch als Teil meines Blogs zu finden HIER .

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

Das erste, was Sie in jQuery lernen, ist, Code innerhalb der Funktion $(document).ready() aufzurufen, damit alles wie folgt ausgeführt wird sobald das DOM geladen ist. In jQuery Mobile wird Ajax jedoch verwendet, um den Inhalt jeder Seite beim Navigieren in das DOM zu laden. Aus diesem Grund wird $(document).ready() ausgelöst, bevor Ihre erste Seite geladen wird, und jeder Code, der für die Seitenmanipulation vorgesehen ist, wird nach einer Seitenaktualisierung ausgeführt. Dies kann ein sehr subtiler Fehler sein. Auf einigen Systemen scheint es, dass es gut funktioniert, aber auf anderen kann es zu unregelmäßigen, schwer zu wiederholenden Verrücktheiten kommen.

Klassische jQuery-Syntax:

$(document).ready(function() {

});

Um dieses Problem zu lösen (und glauben Sie mir, dies ist ein Problem) jQuery Mobile haben Entwickler Seitenereignisse erstellt. Kurz gesagt sind Seitenereignisse Ereignisse, die an einem bestimmten Punkt der Seitenausführung ausgelöst werden. Eines dieser Seitenereignisse ist ein pageinit -Ereignis und wir können es folgendermaßen verwenden:

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

});

Wir können sogar noch weiter gehen und eine Seiten-ID anstelle der Dokumentauswahl verwenden. Angenommen, wir haben eine jQuery Mobile-Seite mit einer 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>

Um Code auszuführen, der nur für die Indexseite verfügbar ist, können wir die folgende Syntax verwenden:

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

});

Pageinit Das Ereignis wird jedes Mal ausgeführt, wenn die Seite zum ersten Mal geladen und angezeigt wird. Es wird nicht erneut ausgelöst, es sei denn, die Seite wird manuell aktualisiert oder das Laden von Ajax-Seiten ist deaktiviert. Wenn Sie möchten, dass der Code bei jedem Besuch einer Seite ausgeführt wird, sollten Sie pagebeforeshow event verwenden.

Hier ist ein funktionierendes Beispiel: http://jsfiddle.net/Gajotres/Q3Usv/ um dieses Problem zu demonstrieren.

Noch ein paar Anmerkungen zu dieser Frage. Unabhängig davon, ob Sie mehrere HTML-Seiten oder mehrere HTML-Dateien verwenden, wird empfohlen, die gesamte Behandlung Ihrer benutzerdefinierten JavaScript-Seiten in eine einzige separate JavaScript-Datei zu unterteilen. Dadurch wird Ihr Code zwar verbessert, Sie erhalten jedoch eine bessere Übersicht über den Code, insbesondere beim Erstellen einer jQuery Mobile -Anwendung.

Es gibt auch ein anderes spezielles jQuery Mobile Ereignis, das mobileinit heißt. Wenn jQuery Mobile gestartet wird, wird ein mobileinit -Ereignis für das Dokumentobjekt ausgelöst. Um die Standardeinstellungen zu überschreiben, binden Sie sie an mobileinit . Ein gutes Beispiel für die Verwendung von mobileinit ist das Deaktivieren des Ladens von Ajax-Seiten oder das Ändern des Standardverhaltens des Ajax-Ladeprogramms.

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

Übergangsreihenfolge für Seitenereignisse

Zunächst finden Sie alle Veranstaltungen hier: http://api.jquerymobile.com/category/events/

Nehmen wir an, wir haben eine Seite A und eine Seite B, dies ist eine Entlade-/Ladereihenfolge:

  1. seite B - event pagebeforecreate

  2. seite B - event pagecreate

  3. seite B - event pageinit

  4. seite A - event pagebeforehide

  5. seite A - event pageremove

  6. seite A - event pagehide

  7. seite B - event pagebeforeshow

  8. seite B - event pageshow

Zum besseren Verständnis von Seitenereignissen lesen Sie bitte folgendes:

  • pagebeforeload, pageload und pageloadfailed werden beim Laden einer externen Seite ausgelöst
  • pagebeforechange, pagechange und pagechangefailed sind Seitenwechselereignisse. Diese Ereignisse werden ausgelöst, wenn ein Benutzer zwischen Seiten in den Anwendungen navigiert.
  • pagebeforeshow, pagebeforehide, pageshow und pagehide sind Seitenübergangsereignisse. Diese Ereignisse werden vor, während und nach einem Übergang ausgelöst und benannt.
  • pagebeforecreate, pagecreate und pageinit dienen zur Seiteninitialisierung.
  • pageremove kann ausgelöst und dann verarbeitet werden, wenn eine Seite aus dem DOM entfernt wird

Beispiel für das Laden von jsFiddle: http://jsfiddle.net/Gajotres/QGnft/

Wenn AJAX nicht aktiviert ist, werden einige Ereignisse möglicherweise nicht ausgelöst.

Seitenübergang verhindern

Wenn aus irgendeinem Grund ein Seitenübergang unter bestimmten Bedingungen verhindert werden muss, kann dies mit folgendem Code erfolgen:

$(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');;
        }
    }
});

Dieses Beispiel funktioniert in jedem Fall, da es bei jedem Seitenübergang ausgelöst wird und, was am wichtigsten ist, einen Seitenwechsel verhindert, bevor ein Seitenübergang stattfinden kann.

Hier ist ein funktionierendes Beispiel:

Verhindern Sie das Binden/Auslösen mehrerer Ereignisse

jQuery Mobile funktioniert anders als klassische Webanwendungen. Abhängig davon, wie Sie es geschafft haben, Ihre Ereignisse bei jedem Besuch einer Seite zu binden, werden Ereignisse immer wieder gebunden. Dies ist kein Fehler, es ist einfach, wie jQuery Mobile seine Seiten behandelt. Schauen Sie sich zum Beispiel diesen Codeausschnitt an:

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

Funktionierendes jsFiddle-Beispiel: http://jsfiddle.net/Gajotres/CCfL4/

Bei jedem Besuch der Seite wird # index click event an button # test-button gebunden. Testen Sie es, indem Sie mehrmals von Seite 1 auf Seite 2 und zurück wechseln. Es gibt einige Möglichkeiten, um dieses Problem zu vermeiden:

Lösung 1

Die beste Lösung wäre, pageinit zu verwenden, um Ereignisse zu binden. Wenn Sie sich eine offizielle Dokumentation ansehen, werden Sie feststellen, dass pageinit NUR einmal ausgelöst wird, genau wie document ready, sodass Ereignisse nicht gebunden werden können nochmal. Dies ist die beste Lösung, da Sie keinen Verarbeitungsaufwand haben, wie beim Entfernen von Ereignissen mit der Methode off.

Funktionierendes jsFiddle-Beispiel: http://jsfiddle.net/Gajotres/AAFH8/

Diese funktionierende Lösung basiert auf einem früheren problematischen Beispiel.

Lösung 2

Entfernen Sie das Ereignis, bevor Sie es binden:

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

Funktionierendes jsFiddle-Beispiel: http://jsfiddle.net/Gajotres/K8YmG/

Lösung 3

Verwenden Sie einen jQuery Filter-Selektor wie folgt:

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

Da der Ereignisfilter kein Teil des offiziellen jQuery-Frameworks ist, finden Sie ihn hier: http://www.codenothing.com/archives/2009/event-filter/

Kurz gesagt, wenn Geschwindigkeit Ihr Hauptanliegen ist, ist Lösung 2 viel besser als Lösung 1.

Lösung 4

Eine neue, wahrscheinlich die einfachste von allen.

$(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;
        }
    });
});

Funktionierendes jsFiddle-Beispiel: http://jsfiddle.net/Gajotres/Yerv9/

Dank an sholsinger für diese Lösung: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/

pageChange event quirks - zweimal auslösen

Manchmal kann ein Seitenwechsel-Ereignis zweimal ausgelöst werden und hat nichts mit dem zuvor genannten Problem zu tun.

Der Grund dafür, dass das pagebeforechange-Ereignis zweimal auftritt, ist der rekursive Aufruf in changePage, wenn toPage kein durch jQuery erweitertes DOM-Objekt ist. Diese Rekursion ist gefährlich, da der Entwickler die toPage innerhalb des Ereignisses ändern darf. Wenn der Entwickler in der Ereignisbehandlungsroutine pagebeforechange konsistent den Wert Page für eine Zeichenfolge festlegt, wird unabhängig davon, ob es sich um ein Objekt handelt oder nicht, eine Endlosrekursivschleife ausgelöst. Das pageload-Ereignis übergibt die neue Seite als Seiteneigenschaft des Datenobjekts (Diese sollte der Dokumentation hinzugefügt werden, sie ist derzeit nicht aufgeführt). Das Ereignis pageload könnte daher verwendet werden, um auf die geladene Seite zuzugreifen.

In wenigen Worten geschieht dies, weil Sie zusätzliche Parameter über pageChange senden.

Beispiel:

<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>

Um dieses Problem zu beheben, verwenden Sie ein beliebiges Seitenereignis, das in Reihenfolge der Seitenereignisse aufgeführt ist.

Seitenwechselzeiten

Wie bereits erwähnt, treten beim Wechsel von einer jQuery Mobile-Seite zu einer anderen in der Regel entweder durch Klicken auf einen Link zu einer anderen, bereits im DOM vorhandenen jQuery Mobile-Seite oder durch manuellen Aufruf von $ .mobile.changePage mehrere Ereignisse und nachfolgende Aktionen auf. Auf hoher Ebene werden folgende Aktionen ausgeführt:

  • Ein Seitenwechselvorgang wird gestartet
  • Eine neue Seite wird geladen
  • Der Inhalt für diese Seite ist "erweitert" (gestylt)
  • Es findet ein Übergang (Folie/Pop/usw.) von der vorhandenen Seite zur neuen Seite statt

Dies ist ein durchschnittlicher Seitenübergangs-Benchmark:

Laden und Verarbeiten der Seite: 3 ms

Seitenerweiterung: 45 ms

Übergang: 604 ms

Gesamtzeit: 670 ms

* Diese Werte sind in Millisekunden angegeben.

Wie Sie sehen, beansprucht ein Übergangsereignis fast 90% der Ausführungszeit.

Manipulation von Daten/Parametern zwischen Seitenübergängen

Es ist möglich, während des Seitenübergangs einen oder mehrere Parameter von einer Seite zur anderen zu senden. Dies kann auf verschiedene Arten geschehen.

Referenz: https://stackoverflow.com/a/13932240/18486

Lösung 1:

Sie können Werte mit changePage übergeben:

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

Und lies sie so:

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

Beispiel :

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>

second.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>

Lösung 2:

Sie können auch ein dauerhaftes JavaScript-Objekt für Speicherzwecke erstellen. Solange Ajax zum Laden von Seiten verwendet wird (und die Seite in keiner Weise neu geladen wird), bleibt dieses Objekt aktiv.

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

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

Lösung 3:

Sie können auch wie folgt auf Daten von der vorherigen Seite zugreifen:

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

prevPage Objekt enthält eine vollständige vorherige Seite.

Lösung 4:

Als letzte Lösung haben wir eine raffinierte HTML-Implementierung von localStorage. Es funktioniert nur mit HTML5-Browsern (einschließlich Android und iOS-Browser)), aber alle gespeicherten Daten bleiben durch Seitenaktualisierung erhalten.

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

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

Wahrscheinlich die beste Lösung, aber in einigen Versionen von iOS 5.X wird es fehlschlagen. Es ist ein bekannter Fehler.

Verwenden Sie nicht .live()/.bind()/.delegate()

Ich habe vergessen zu erwähnen (und tnx andleer , um mich daran zu erinnern), dass On/Off für das Binden/Entbinden von Ereignissen, Live/Die und Binden/Entbinden veraltet sind.

Die .live () -Methode von jQuery wurde als Glücksfall angesehen, als sie in Version 1.3 in die API eingeführt wurde. In einer typischen jQuery-App kann eine Menge DOM-Manipulationen vorgenommen werden, und es kann sehr mühsam werden, Elemente beim Kommen und Gehen anzuhängen und abzuhängen. Die .live() -Methode ermöglichte das Verknüpfen eines Ereignisses für die Lebensdauer der App basierend auf dessen Auswahl. Großartig, oder? Falsch, die .live() Methode ist extrem langsam. Die .live() -Methode verknüpft ihre Ereignisse tatsächlich mit dem Dokumentobjekt. Dies bedeutet, dass das Ereignis von dem Element, das das Ereignis generiert hat, in die Luft gesprudelt werden muss, bis es das Dokument erreicht. Dies kann erstaunlich zeitaufwändig sein.

Es ist jetzt veraltet. Die Leute im jQuery-Team empfehlen die Verwendung nicht mehr und ich auch nicht. Auch wenn es mühsam sein kann, Ereignisse zu verknüpfen und zu trennen, ist Ihr Code ohne die .live() -Methode viel schneller als mit ihr.

Anstelle von .live() sollten Sie .on() verwenden. .on() ist ca. 2-3x schneller als . live () . Schauen Sie sich diesen Benchmark für Event-Bindungen an: http://jsperf.com/jquery-live-vs-delegate-vs-on/34 , von dort wird alles klar.

Benchmarking:

Es gibt ein exzellentes Skript für das jQuery Mobile Benchmarking von Seitenereignissen. Es kann hier gefunden werden: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js . Aber bevor Sie etwas tun, rate ich Ihnen, das alert Benachrichtigungssystem zu entfernen (jede "Änderungsseite" wird Ihnen diese Daten anzeigen, indem Sie die App anhalten ) und ändere es auf console.log function.

Grundsätzlich protokolliert dieses Skript alle Ihre Seitenereignisse. Wenn Sie diesen Artikel sorgfältig lesen (Seitenereignisbeschreibungen), wissen Sie, wie viel Zeit jQm für Seitenverbesserungen und Seitenübergänge aufgewendet hat.

Schlussnoten

Immer, und ich meine immer offizielle jQuery Mobile Dokumentation lesen. In der Regel erhalten Sie die erforderlichen Informationen. Im Gegensatz zu anderen Dokumentationen ist diese ziemlich gut und enthält genügend Erklärungen und Codebeispiele.

Änderungen:

  • 30.01.2013 - Es wurde eine neue Methode zur Verhinderung der Auslösung mehrerer Ereignisse hinzugefügt
  • 31.01.2013 - Eine bessere Klarstellung für das Kapitel Daten/Parameter-Manipulation zwischen Seitenübergängen wurde hinzugefügt
  • 03.02.2013 - Es wurden neue Inhalte/Beispiele zum Kapitel Daten/Parameter-Manipulation zwischen Seitenübergängen hinzugefügt
  • 22.05.2013 - Eine Lösung zur Verhinderung von Seitenübergängen/-änderungen und Links zur offiziellen API-Dokumentation für Seitenereignisse wurden hinzugefügt
  • 18.05.2013 - Eine weitere Lösung gegen die Bindung mehrerer Ereignisse wurde hinzugefügt
438
Gajotres

Einige von Ihnen mögen dies nützlich finden. Kopieren Sie es einfach und fügen Sie es auf Ihrer Seite ein. Sie erhalten eine Sequenz, in der Ereignisse in der Chrome console (Ctrl + Shift + I).

$(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');});

In der Konsole wird kein Entladen angezeigt, da es ausgelöst wird, wenn die Seite entladen wird (wenn Sie sich von der Seite entfernen). Benutze es so:

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

Und du wirst sehen, was ich meine.

17

Das ist der richtige Weg:

Um Code auszuführen, der nur für die Indexseite verfügbar ist, können Sie die folgende Syntax verwenden:

$(document).on('pageinit', "#index",  function() {
    ...
});
3
kecco

Der einfache Unterschied zwischen document ready und page event in jQuery-mobile besteht darin, dass:

  1. Das document ready-Ereignis wird für die gesamte HTML-Seite verwendet.

    $(document).ready(function(e) {
        // Your code
    });
    
  2. Wenn es ein Seitenereignis gibt, verwenden Sie für die Behandlung eines bestimmten Seitenereignisses:

    <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-->
    

Sie können document auch zur Behandlung des pageinit-Ereignisses verwenden:

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

});
1
LeoMobDev