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 alte Art der Handhabung ist jetzt veraltet und bleibt bis (einschließlich) jQuery Mobile 1.5 aktiv, sodass Sie alle unten genannten Elemente mindestens bis zum nächsten Jahr und jQuery Mobile 1.6 verwenden können.
Alte Ereignisse, einschließlich pageinit , existieren nicht mehr, sie werden durch das Seitencontainer- Widget ersetzt. Pageinit wird vollständig gelöscht und Sie können stattdessen pagecreate verwenden. Dieses Ereignis ist gleich geblieben und wird nicht geändert.
Wenn Sie an einer neuen Art der Behandlung von Seitenereignissen interessiert sind, schauen Sie hier , in jedem anderen Fall 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 HIER zu finden .
$(document).on('pageinit')
vs. $(document).ready()
Das erste, was Sie in jQuery lernen, ist das Aufrufen von Code innerhalb der $(document).ready()
Funktion, damit alles ausgeführt wird, sobald das DOM geladen wird. In jQuery Mobile wird Ajax jedoch verwendet, um den Inhalt jeder Seite während der Navigation in das DOM zu laden. Aus diesem Grund $(document).ready()
wird 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, auf anderen kann es jedoch zu unregelmäßigen, schwer zu wiederholenden Verrücktheiten kommen.
Klassische jQuery-Syntax:
$(document).ready(function() {
});
Um dieses Problem zu lösen (und mir zu vertrauen, dass dies ein Problem ist), haben jQuery Mobile- Entwickler Seitenereignisse erstellt. Kurz gesagt, Seitenereignisse sind 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 noch weiter gehen und eine Seiten-ID anstelle der Dokumentauswahl verwenden. Angenommen, wir haben eine jQuery Mobile-Seite mit einem 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 diese Syntax verwenden:
$('#index').on('pageinit', function() {
});
Das Pageinit- Ereignis wird jedes Mal ausgeführt, wenn eine Seite geladen und zum ersten Mal angezeigt wird. Es wird erst wieder ausgelöst, wenn die Seite manuell aktualisiert oder das Laden der Ajax-Seite deaktiviert wurde. Wenn Sie möchten, dass Code bei jedem Besuch einer Seite ausgeführt wird, ist es besser, das Ereignis pagebeforeshow zu verwenden .
Hier ist ein funktionierendes Beispiel: http://jsfiddle.net/Gajotres/Q3Usv/ , um dieses Problem zu demonstrieren.
Einige weitere Anmerkungen zu dieser Frage. Unabhängig davon, ob Sie 1 HTML-Paradigma für mehrere Seiten oder mehrere HTML-Dateien verwenden, wird empfohlen, die gesamte benutzerdefinierte Behandlung von JavaScript-Seiten in eine einzige separate JavaScript-Datei zu unterteilen. Dadurch wird Ihr Code besser, aber Sie haben eine viel bessere Codeübersicht, insbesondere beim Erstellen einer jQuery Mobile- Anwendung.
Es gibt auch ein weiteres spezielles jQuery Mobile- Ereignis, das mobileinit heißt . Wenn jQuery Mobile gestartet wird , wird ein mobileinit- Ereignis für das Dokumentobjekt ausgelöst . Um Standardeinstellungen zu überschreiben, binden Sie sie an mobileinit . Eines der guten Beispiele für die Verwendung von mobileinit ist das Deaktivieren des Ladens von Ajax-Seiten oder das Ändern des Standardverhaltens von Ajax Loader.
$(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:
Seite B - Ereignisseite vor dem Erstellen
Seite B - Ereignisseite erstellen
Seite B - Ereignis Pageinit
Seite A - Ereignisseite vor dem Ausblenden
Seite A - Ereignis- Pageremove
Seite A - Ereignis pagehide
Seite B - Ereignisseite vor der Show
Seite B - Ereignis pageshow
Zum besseren Verständnis von Seitenereignissen lesen Sie Folgendes:
pagebeforeload
, pageload
Und pageloadfailed
werden ausgelöst , wenn eine externe Seite geladen wird
pagebeforechange
, pagechange
Und pagechangefailed
sind Seite Änderungsereignisse. Diese Ereignisse werden ausgelöst, wenn ein Benutzer zwischen Seiten in den Anwendungen navigiert.
pagebeforeshow
, pagebeforehide
, pageshow
Und pagehide
sind Seite Übergangsereignisse. Diese Ereignisse werden vor, während und nach einem Übergang ausgelöst und benannt.
pagebeforecreate
, pagecreate
Und pageinit
sind für Seite Initialisierung.
pageremove
kann ausgelöst und dann verarbeitet werden, wenn eine Seite aus dem DOM entfernt wird
Beispiel zum Laden einer Seite 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 der 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 Arbeitsbeispiel:
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, sondern lediglich der Umgang jQuery Mobile
mit den Seiten. Schauen Sie sich zum Beispiel dieses Code-Snippet an:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
Beispiel für ein funktionierendes jsFiddle: http://jsfiddle.net/Gajotres/CCfL4/
Jedes Mal, wenn Sie das Ereignis #index click auf Seite # besuchen, wird es an die Schaltfläche # test-button gebunden . Testen Sie es, indem Sie mehrmals von Seite 1 zu Seite 2 und zurück wechseln. Es gibt nur wenige Möglichkeiten, um dieses Problem zu vermeiden:
Lösung 1
Die beste Lösung wäre, pageinit
Ereignisse zu binden. Wenn Sie sich eine offizielle Dokumentation ansehen, werden Sie feststellen, dass pageinit
sie NUR einmal ausgelöst wird, genau wie das Dokument, sodass Ereignisse auf keinen Fall erneut gebunden werden können. Dies ist die beste Lösung, da Sie keinen Verarbeitungsaufwand haben, wie beim Entfernen von Ereignissen mit der Off-Methode.
Beispiel für ein funktionierendes jsFiddle: http://jsfiddle.net/Gajotres/AAFH8/
Diese Arbeitslö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');
});
});
Beispiel für ein funktionierendes jsFiddle: 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 nicht 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
Ein neuer, wahrscheinlich der 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;
}
});
});
Beispiel für ein funktionierendes jsFiddle: http://jsfiddle.net/Gajotres/Yerv9/
Vielen Dank an den Sholsinger für diese Lösung: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
pageChange-Ereignismacken - zweimaliges Auslösen
Manchmal kann ein Seitenwechselereignis zweimal ausgelöst werden und hat nichts mit dem zuvor erwähnten Problem zu tun.
Der Grund, warum das Ereignis pagebeforechange zweimal auftritt, ist der rekursive Aufruf in changePage, wenn toPage kein jQuery-erweitertes DOM-Objekt ist. Diese Rekursion ist gefährlich, da der Entwickler die toPage innerhalb des Ereignisses ändern darf. Wenn der Entwickler konsistent toPage auf eine Zeichenfolge setzt, wird innerhalb des Ereignishandlers pagebeforechange unabhängig davon, ob es sich um ein Objekt handelt oder nicht, eine unendliche rekursive Schleife erstellt. Das pageload-Ereignis übergibt die neue Seite als Seiteneigenschaft des Datenobjekts (Dies sollte der Dokumentation hinzugefügt werden, es ist derzeit nicht aufgeführt). Das pageload-Ereignis kann 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&name=Sat"><h3>Sat</h3></a>
Um dieses Problem zu beheben, verwenden Sie ein beliebiges Seitenereignis, das in der Übergangsreihenfolge für Seitenereignisse aufgeführt ist .
Seitenwechselzeiten
Wie bereits erwähnt, treten beim Wechsel von einer jQuery Mobile-Seite zu einer anderen in der Regel mehrere Ereignisse und nachfolgende Aktionen auf, indem Sie entweder auf einen Link zu einer anderen bereits im DOM vorhandenen jQuery Mobile-Seite klicken oder $ .mobile.changePage manuell aufrufen. Auf hoher Ebene treten folgende Aktionen auf:
- Ein Seitenwechselprozess wird gestartet
- Eine neue Seite wird geladen
- Der Inhalt dieser Seite ist "erweitert" (gestaltet)
- Es erfolgt ein Übergang (Folie / Pop / etc) von der vorhandenen Seite zur neuen Seite
Dies ist ein durchschnittlicher Benchmark für den Seitenübergang:
Laden und Verarbeiten von Seiten : 3 ms
Seitenverbesserung: 45 ms
Übergang: 604 ms
Gesamtzeit: 670 ms
* Diese Werte sind in Millisekunden angegeben.
Wie Sie sehen, verbraucht ein Übergangsereignis fast 90% der Ausführungszeit.
Daten- / Parametermanipulation 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/1848600
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);
});
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:
Oder Sie können ein dauerhaftes JavaScript-Objekt für einen Speicherzweck 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'));
});
Das 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-Browsern), 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 sie wird in einigen Versionen von iOS 5.X 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 Ein / Aus 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 es zu vielen DOM-Manipulationen kommen, und es kann sehr mühsam werden, beim Ein- und Aussteigen von Elementen ein- und auszuhängen. Die .live()
Methode ermöglichte es, ein Ereignis für die Lebensdauer der App basierend auf ihrer Auswahl zu verknüpfen. 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 aus dem Element, das das Ereignis generiert hat, sprudeln 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 das Ein- und Aushängen von Ereignissen mühsam sein kann, ist Ihr Code ohne die .live()
Methode viel schneller als mit dieser.
Anstelle von .live()
sollten Sie verwenden .on()
. .on()
ist ungefähr 2-3x schneller als .live () . Schauen Sie sich diesen ereignisbindenden Benchmark an: http://jsperf.com/jquery-live-vs-delegate-vs-on/34 , von dort aus wird alles klar.
Benchmarking:
Es gibt ein hervorragendes Skript für das Benchmarking von jQuery Mobile- Seitenereignissen. Es kann hier gefunden werden: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js . Bevor Sie jedoch etwas damit anfangen, empfehle ich Ihnen, das alert
Benachrichtigungssystem zu entfernen (jede „Änderungsseite“ zeigt Ihnen diese Daten an, indem Sie die App anhalten) und sie in die console.log
Funktion zu ändern .
Grundsätzlich protokolliert dieses Skript alle Ihre Seitenereignisse. Wenn Sie diesen Artikel sorgfältig lesen (Beschreibungen der Seitenereignisse), wissen Sie, wie viel Zeit jQm für Seitenverbesserungen, Seitenübergänge usw. aufgewendet hat.
Schlussbemerkungen
Lesen Sie immer die offizielle jQuery Mobile- Dokumentation. In der Regel erhalten Sie die erforderlichen Informationen, und im Gegensatz zu anderen Dokumentationen ist diese ziemlich gut, mit genügend Erklärungen und Codebeispielen.
Änderungen:
- 30.01.2013 - Eine neue Methode zur Verhinderung der Auslösung mehrerer Ereignisse wurde hinzugefügt
- 31.01.2013 - Bessere Erläuterung für das Kapitel Daten- / Parametermanipulation zwischen Seitenübergängen hinzugefügt
- 03.02.2013 - Neue Inhalte / Beispiele zum Kapitel Daten- / Parametermanipulation zwischen Seitenübergängen hinzugefügt
- 22.05.2013 - Es wurde eine Lösung zur Verhinderung von Seitenübergängen / -änderungen hinzugefügt und Links zur offiziellen API-Dokumentation für Seitenereignisse hinzugefügt
- 18.05.2013 - Eine weitere Lösung gegen die Bindung mehrerer Ereignisse wurde hinzugefügt