Aggiornamento di jQuery Mobile 1.4:
Il mio articolo originale era destinato al vecchio modo di gestire le pagine, praticamente tutto prima di jQuery Mobile 1.4. Il vecchio modo di gestire è ora deprecato e rimarrà attivo fino (incluso) a jQuery Mobile 1.5, quindi è ancora possibile utilizzare tutto quanto indicato di seguito, almeno fino al prossimo anno e jQuery Mobile 1.6.
I vecchi eventi, incluso pageinit , non esistono più, vengono sostituiti con il widget pagecontainer . Pageinit viene completamente cancellato e puoi usare invece pagecreate , quell'evento è rimasto lo stesso e non verrà modificato.
Se sei interessato a un nuovo modo di gestire gli eventi della pagina dai un'occhiata qui , in ogni caso sentiti libero di continuare con questo articolo. Dovresti leggere questa risposta anche se stai usando jQuery Mobile 1.4 +, va oltre gli eventi di pagina, quindi troverai probabilmente molte informazioni utili.
Contenuto precedente:
Questo articolo può anche essere trovato come una parte del mio blog QUI .
$(document).on('pageinit')
vs $(document).ready()
La prima cosa che impari in jQuery è chiamare il codice all'interno della $(document).ready()
funzione in modo che tutto venga eseguito non appena viene caricato il DOM. Tuttavia, in jQuery Mobile , Ajax viene utilizzato per caricare i contenuti di ciascuna pagina nel DOM durante la navigazione. Per questo $(document).ready()
motivo si attiverà prima che la tua prima pagina venga caricata e ogni codice destinato alla manipolazione della pagina verrà eseguito dopo un aggiornamento della pagina. Questo può essere un bug molto sottile. In alcuni sistemi può sembrare che funzioni bene, ma in altri può causare stranezze irregolari, difficili da ripetere.
Sintassi classica di jQuery:
$(document).ready(function() {
});
Per risolvere questo problema (e credetemi, questo è un problema) gli sviluppatori di jQuery Mobile hanno creato eventi di pagina. In breve, gli eventi della pagina sono eventi attivati in un particolare punto dell'esecuzione della pagina. Uno di quegli eventi di pagina è un evento di pageinit e possiamo usarlo in questo modo:
$(document).on('pageinit', function() {
});
Possiamo andare ancora oltre e utilizzare un ID pagina anziché il selettore documenti. Supponiamo di avere una pagina jQuery Mobile con un indice ID :
<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>
Per eseguire il codice che sarà disponibile solo per la pagina dell'indice, potremmo usare questa sintassi:
$('#index').on('pageinit', function() {
});
L' evento Pageinit verrà eseguito ogni volta che la pagina sta per essere caricata e mostrata per la prima volta. Non si attiverà più a meno che la pagina non venga aggiornata manualmente o il caricamento della pagina Ajax sia disattivato. Nel caso in cui desideri che il codice venga eseguito ogni volta che visiti una pagina, è meglio utilizzare l' evento pagebeforeshow .
Ecco un esempio funzionante: http://jsfiddle.net/Gajotres/Q3Usv/ per dimostrare questo problema.
Poche altre note su questa domanda. Indipendentemente se si utilizza 1 html di più pagine o paradigma di più file HTML, si consiglia di separare tutta la gestione della pagina JavaScript personalizzata in un singolo file JavaScript separato. Questo renderà il tuo codice ancora migliore, ma avrai una panoramica del codice molto migliore, specialmente durante la creazione di un'applicazione jQuery Mobile .
C'è anche un altro evento speciale su jQuery Mobile e si chiama mobileinit . All'avvio di jQuery Mobile , viene attivato un evento mobileinit sull'oggetto documento. Per sovrascrivere le impostazioni predefinite, associale a mobileinit . Uno dei buoni esempi dell'utilizzo di mobileinit è la disattivazione del caricamento della pagina Ajax o la modifica del comportamento predefinito del caricatore Ajax.
$(document).on("mobileinit", function(){
//apply overrides here
});
Ordine di transizione degli eventi della pagina
Innanzitutto tutti gli eventi possono essere trovati qui: http://api.jquerymobile.com/category/events/
Diciamo che abbiamo una pagina A e una pagina B, questo è un ordine di scarico / caricamento:
pagina B - pagina dell'evento per creare
pagina B - pagecreate evento
pagina B - evento pageinit
pagina A - pagina dell'evento prima
pagina A - evento pageremove
pagina A - evento pagehide
pagina B - evento pagebeforeshow
pagina B - mostra pagine dell'evento
Per una migliore comprensione degli eventi della pagina leggi questo:
pagebeforeload
, pageload
E pageloadfailed
sono attivato quando una pagina esterna viene caricata
pagebeforechange
, pagechange
E pagechangefailed
sono pagina eventi di modifica. Questi eventi vengono generati quando un utente sta navigando tra le pagine delle applicazioni.
pagebeforeshow
, pagebeforehide
, pageshow
E pagehide
sono gli eventi di transizione di pagina. Questi eventi vengono generati prima, durante e dopo una transizione e vengono denominati.
pagebeforecreate
, pagecreate
E pageinit
sono per la pagina di inizializzazione.
pageremove
può essere attivato e quindi gestito quando una pagina viene rimossa dal DOM
Caricamento pagina js Esempio di esempio: http://jsfiddle.net/Gajotres/QGnft/
Se AJAX non è abilitato, alcuni eventi potrebbero non attivarsi.
Impedisci la transizione della pagina
Se per qualche motivo la transizione della pagina deve essere impedita in alcune condizioni, può essere eseguita con questo codice:
$(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');;
}
}
});
Questo esempio funzionerà in ogni caso perché si attiverà in seguito a una supplica di ogni transizione di pagina e ciò che è più importante impedirà il cambio di pagina prima che possa avvenire la transizione di pagina.
Ecco un esempio funzionante:
Prevenire l'associazione / l'attivazione di più eventi
jQuery Mobile
funziona in modo diverso rispetto alle classiche applicazioni Web. A seconda di come sei riuscito a legare i tuoi eventi ogni volta che visiti una pagina, rileverà gli eventi più e più volte. Questo non è un errore, è semplicemente come jQuery Mobile
gestisce le sue pagine. Ad esempio, dai un'occhiata a questo frammento di codice:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
Esempio js funzionante: http://jsfiddle.net/Gajotres/CCfL4/
Ogni volta che visiti la pagina #index, l' evento sarà associato al pulsante # test-pulsante . Provalo passando da pagina 1 a pagina 2 e viceversa più volte. Esistono alcuni modi per prevenire questo problema:
Soluzione 1
La soluzione migliore sarebbe utilizzare pageinit
per associare gli eventi. Se dai un'occhiata a una documentazione ufficiale, scoprirai che pageinit
si attiverà SOLO una volta, proprio come il documento pronto, quindi non c'è modo che gli eventi vengano rilegati di nuovo. Questa è la soluzione migliore perché non hai un overhead di elaborazione come quando rimuovi eventi con il metodo off.
Esempio js funzionante: http://jsfiddle.net/Gajotres/AAFH8/
Questa soluzione funzionante è realizzata sulla base di un precedente esempio problematico.
Soluzione 2
Rimuovi l'evento prima di associarlo:
$(document).on('pagebeforeshow', '#index', function(){
$(document).off('click', '#test-button').on('click', '#test-button',function(e) {
alert('Button click');
});
});
Esempio js funzionante: http://jsfiddle.net/Gajotres/K8YmG/
Soluzione 3
Utilizzare un selettore filtro jQuery, in questo modo:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Poiché il filtro eventi non fa parte del framework jQuery ufficiale, è possibile trovarlo qui: http://www.codenothing.com/archives/2009/event-filter/
In breve, se la velocità è la tua preoccupazione principale, la Soluzione 2 è molto meglio della Soluzione 1.
Soluzione 4
Uno nuovo, probabilmente il più semplice di tutti.
$(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;
}
});
});
Esempio js funzionante: http://jsfiddle.net/Gajotres/Yerv9/
Grazie allo sholsinger per questa soluzione: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
Quirks di eventi pageChange - attivazione due volte
A volte l'evento pagechange può attivarsi due volte e non ha nulla a che fare con il problema menzionato in precedenza.
Il motivo per cui l'evento pagebeforechange si verifica due volte è dovuto alla chiamata ricorsiva in changePage quando toPage non è un oggetto DOM avanzato jQuery. Questa ricorsione è pericolosa, in quanto allo sviluppatore è consentito modificare la pagina all'interno dell'evento. Se lo sviluppatore imposta costantemente su Pagina su una stringa, all'interno del gestore di eventi pagebeforechange, indipendentemente dal fatto che si trattasse o meno di un oggetto, si verificherà un ciclo ricorsivo infinito. L'evento pageload passa la nuova pagina come proprietà page dell'oggetto dati (questo dovrebbe essere aggiunto alla documentazione, non è attualmente elencato). L'evento pageload potrebbe quindi essere utilizzato per accedere alla pagina caricata.
In poche parole ciò accade perché si inviano parametri aggiuntivi tramite pageChange.
Esempio:
<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>
Per risolvere questo problema, utilizzare qualsiasi evento di pagina elencato nell'ordine di transizione degli eventi di pagina .
Tempi di cambio pagina
Come accennato, quando si passa da una pagina jQuery Mobile a un'altra, in genere facendo clic su un collegamento a un'altra pagina jQuery Mobile già esistente nel DOM o chiamando manualmente $ .mobile.changePage, si verificano numerosi eventi e azioni successive. Ad un livello elevato si verificano le seguenti azioni:
- Viene avviato un processo di modifica della pagina
- Viene caricata una nuova pagina
- Il contenuto di quella pagina è "migliorato" (stile)
- Si verifica una transizione (diapositiva / pop / ecc.) Dalla pagina esistente alla nuova pagina
Questo è un benchmark medio di transizione delle pagine:
Caricamento ed elaborazione della pagina: 3 ms
Miglioramento della pagina: 45 ms
Transizione: 604 ms
Tempo totale: 670 ms
* Questi valori sono espressi in millisecondi.
Come puoi vedere, un evento di transizione sta consumando quasi il 90% dei tempi di esecuzione.
Manipolazione di dati / parametri tra le transizioni di pagina
È possibile inviare un / i parametro / i da una pagina all'altra durante la transizione della pagina. Può essere fatto in pochi modi.
Riferimento: https://stackoverflow.com/a/13932240/1848600
Soluzione 1:
Puoi passare valori con changePage:
$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });
E leggili in questo modo:
$(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>
Soluzione 2:
Oppure puoi creare un oggetto JavaScript persistente a scopo di archiviazione. Finché Ajax viene utilizzato per il caricamento della pagina (e la pagina non viene ricaricata in alcun modo) quell'oggetto rimarrà attivo.
var storeObject = {
firstname : '',
lastname : ''
}
Esempio: http://jsfiddle.net/Gajotres/9KKbx/
Soluzione 3:
Puoi anche accedere ai dati dalla pagina precedente in questo modo:
$(document).on('pagebeforeshow', '#index',function (e, data) {
alert(data.prevPage.attr('id'));
});
L' oggetto prevPage contiene una pagina precedente completa.
Soluzione 4:
Come ultima soluzione, abbiamo un'importante implementazione HTML di localStorage. Funziona solo con i browser HTML5 (inclusi i browser Android e iOS) ma tutti i dati memorizzati sono persistenti attraverso l'aggiornamento della pagina.
if(typeof(Storage)!=="undefined") {
localStorage.firstname="Dragan";
localStorage.lastname="Gaic";
}
Esempio: http://jsfiddle.net/Gajotres/J9NTr/
Probabilmente la soluzione migliore ma fallirà in alcune versioni di iOS 5.X. È un errore ben noto.
Non usare .live()
/ .bind()
/.delegate()
Ho dimenticato di menzionare (e tnx andleer per avermi ricordato) l'uso on / off per il binding / unbinding dell'evento, live / die e bind / unbind sono deprecati.
Il metodo .live () di jQuery è stato visto come una manna dal cielo quando è stato introdotto nell'API nella versione 1.3. In una tipica app jQuery può esserci molta manipolazione del DOM e può diventare molto noioso agganciarsi e sganciarsi quando gli elementi vanno e vengono. Il .live()
metodo ha permesso di agganciare un evento per la vita dell'app in base al suo selettore. Ottimo vero? Sbagliato, il .live()
metodo è estremamente lento. Il .live()
metodo in realtà aggancia i suoi eventi all'oggetto documento, il che significa che l'evento deve passare dall'elemento che ha generato l'evento fino a raggiungere il documento. Questo può richiedere incredibilmente tempo.
Ora è deprecato. Le persone del team di jQuery non ne raccomandano più l'uso e nemmeno io. Anche se può essere noioso agganciare e sganciare gli eventi, il tuo codice sarà molto più veloce senza il .live()
metodo che con esso.
Invece di .live()
te dovresti usare .on()
. .on()
è circa 2-3x più veloce di .live () . Dai un'occhiata a questo benchmark vincolante per gli eventi: http://jsperf.com/jquery-live-vs-delegate-vs-on/34 , tutto sarà chiaro da lì.
Analisi comparativa:
Esiste un eccellente script creato per il benchmarking degli eventi di pagina jQuery Mobile . Può essere trovato qui: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js . Ma prima di fare qualsiasi cosa con esso, ti consiglio di rimuovere il suo alert
sistema di notifica (ogni "pagina di modifica" ti mostrerà questi dati arrestando l'app) e cambiarlo per console.log
funzionare.
Fondamentalmente questo script registrerà tutti gli eventi della tua pagina e se leggi attentamente questo articolo (descrizioni degli eventi della pagina) saprai quanto tempo speso jQm per migliorare le pagine, le transizioni di pagina ....
Note finali
Sempre e intendo sempre leggere la documentazione ufficiale di jQuery Mobile . Di solito ti fornirà le informazioni necessarie e, diversamente da qualche altra documentazione, questa è piuttosto buona, con sufficienti spiegazioni ed esempi di codice.
I cambiamenti:
- 30.01.2013 - Aggiunto un nuovo metodo per la prevenzione di eventi multipli
- 31.01.2013 - Aggiunto un migliore chiarimento per la manipolazione dei dati / parametri del capitolo tra le transizioni di pagina
- 03.02.2013 - Aggiunti nuovi contenuti / esempi al capitolo Manipolazione di dati / parametri tra le transizioni di pagina
- 22.05.2013 - Aggiunta una soluzione per la transizione di pagina / prevenzione delle modifiche e collegamenti aggiunti alla documentazione API ufficiale degli eventi di pagina
- 18.05.2013 - Aggiunta un'altra soluzione contro l'associazione di più eventi