Mise à jour de jQuery Mobile 1.4 :
Mon article original était destiné à l'ancienne façon de gérer les pages, c'est-à-dire à tout ce qui existait avant jQuery Mobile 1.4. L'ancienne façon de gérer les pages est maintenant dépréciée et restera active jusqu'à (y compris) jQuery Mobile 1.5, donc 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, notamment pageinit n'existent plus, elles sont remplacées par pagecontainer widget. Pageinit est complètement effacé et vous pouvez utiliser pagecreate Au lieu de cela, cet événement est resté le même et il ne sera pas modifié.
Si vous êtes intéressé par une nouvelle façon de gérer les événements de page, jetez un coup d'œil à la page suivante ici Dans tous les autres cas, n'hésitez pas à poursuivre la lecture de cet article. Vous devriez lire cette réponse même si vous utilisez jQuery Mobile 1.4 +, elle va au-delà des événements de page donc vous trouverez probablement beaucoup d'informations utiles.
Contenu plus ancien :
Cet article peut également être trouvé dans le cadre 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()
afin que tout s'exécute dès que le DOM est chargé. Cependant, en jQuery Mobile Ajax est utilisé pour charger le contenu de chaque page dans le DOM au fur et à mesure de la navigation. En raison de cette $(document).ready()
se déclenchera avant que votre première page ne soit chargée et tout code destiné à la manipulation de la page sera exécuté après un rafraîchissement de la page. Ce bogue peut être très subtil. Sur certains systèmes, il peut sembler fonctionner correctement, mais sur d'autres, il peut provoquer des bizarreries erratiques et difficiles à répéter.
Syntaxe classique de jQuery :
$(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, les événements de page sont des événements déclenchés à un moment particulier de l'exécution de la page. L'un de ces événements de page est un pageinit 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 d'un sélecteur de document. Disons que nous avons une page jQuery Mobile avec un id indice :
<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 un code qui ne sera disponible que sur la page d'index, nous pouvons utiliser cette syntaxe :
$('#index').on('pageinit', function() {
});
Pageinit sera exécuté chaque fois que la page est sur le point d'être chargée et affichée pour la première fois. Il ne se déclenchera plus, sauf si la page est rafraîchie manuellement ou si le chargement de la page par Ajax est désactivé. Si vous souhaitez que le code soit exécuté à chaque fois que vous visitez une page, il est préférable d'utiliser l'événement pageavant l'exposition événement.
Voici un exemple concret : http://jsfiddle.net/Gajotres/Q3Usv/ pour démontrer ce problème.
Quelques notes supplémentaires sur cette question. Peu importe que vous utilisiez 1 page html, plusieurs pages ou plusieurs fichiers HTML, il est conseillé de séparer toutes vos manipulations de pages JavaScript personnalisées dans un seul fichier JavaScript distinct. Cela ne rendra pas votre code meilleur, mais vous aurez une meilleure vue d'ensemble du code, en particulier lors de la création d'une page JavaScript. jQuery Mobile application.
Il y a aussi une autre spéciale jQuery Mobile et il est appelé mobileinit . Quand jQuery Mobile commence, il déclenche un mobileinit sur l'objet document. Pour remplacer les paramètres par défaut, liez-les à mobileinit . Un des bons exemples de mobileinit est de désactiver le chargement des pages par Ajax, ou de modifier le comportement par défaut du chargeur Ajax.
$(document).on("mobileinit", function(){
//apply overrides here
});
Ordre de transition des événements de la page
Tous les premiers é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 :
-
page B - événement pagebeforecreate
-
page B - événement pagecreate
-
page B - événement pageinit
-
page A - événement pagebeforehide
-
page A - événement supprimer la page
-
page A - événement pagehide
-
page B - événement pageavant l'exposition
-
page B - événement pageshow
Pour mieux comprendre les événements de la page, lisez ceci :
-
pagebeforeload
, pageload
et pageloadfailed
sont déclenchées lorsqu'une page externe est chargée
-
pagebeforechange
, pagechange
et pagechangefailed
sont des événements de changement de page. Ces événements sont déclenchés lorsqu'un utilisateur navigue entre les pages des applications.
-
pagebeforeshow
, pagebeforehide
, pageshow
et pagehide
sont des événements de transition de page. Ces événements sont déclenchés avant, pendant et après une transition et sont nommés.
-
pagebeforecreate
, pagecreate
et pageinit
sont pour l'initialisation de la page.
-
pageremove
peut être déclenché et ensuite géré lorsqu'une page est retirée du DOM
Exemple de chargement de 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 sous certaines conditions, ce code peut être utilisé :
$(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 se déclenchera au début 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 se produire.
Voici un exemple concret :
Empêcher la liaison/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 visiterez une page, elle liera des événements encore et encore. Il ne s'agit pas d'une erreur, c'est simplement la façon dont les jQuery Mobile
gère ses pages. Par exemple, jetez un coup d'œil à cet extrait de code :
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
Exemple de jsFiddle fonctionnel : http://jsfiddle.net/Gajotres/CCfL4/
Chaque fois que vous visitez la page #index l'événement de clic sera lié au bouton #test-button . Testez-le en passant de la page 1 à la page 2 et inversement plusieurs fois. Il existe quelques moyens d'éviter ce problème :
Solution 1
La meilleure solution serait d'utiliser pageinit
pour lier les événements. Si vous jetez un coup d'œil à une documentation officielle, vous découvrirez que pageinit
ne se déclenchera qu'une seule fois, tout comme le document ready, de sorte qu'il n'y a aucune chance que les événements soient liés à nouveau. C'est la meilleure solution car vous n'avez pas de surcharge de traitement comme lorsque vous supprimez des événements avec la méthode off.
Exemple de jsFiddle fonctionnel : http://jsfiddle.net/Gajotres/AAFH8/
Cette solution de travail est élaborée sur la base d'un exemple problématique précédent.
Solution 2
Supprimez 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 jsFiddle fonctionnel : 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
});
Comme le filtre d'événements ne fait pas partie du cadre officiel de jQuery, il peut être trouvé ici : http://www.codenothing.com/archives/2009/event-filter/
En bref, si la vitesse est votre principale préoccupation, alors Solution 2 est bien meilleure que la solution 1.
Solution 4
Une nouvelle, probablement la plus facile d'entre elles.
$(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 jsFiddle fonctionnel : 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/
bizarreries de l'événement pageChange - déclenchement double
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 pour laquelle l'événement pagebeforechange se produit deux fois est due à l'appel récursif dans changePage lorsque toPage n'est pas un objet DOM amélioré par jQuery. Cette récursion est dangereuse, car le développeur est autorisé à modifier toPage dans l'événement. Si le développeur définit systématiquement toPage comme une chaîne, dans le gestionnaire d'événement pagebeforechange, qu'il s'agisse ou non d'un objet, une boucle récursive infinie en résultera. L'événement pageload transmet la nouvelle page comme propriété page de l'objet de données (Ceci devrait être ajouté à la documentation, ce n'est pas listé actuellement). L'événement pageload peut 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 par pageChange.
Exemple :
<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>
Pour résoudre ce problème, utilisez n'importe quel événement de page répertorié dans la section Ordre de transition des événements de la page .
Temps de changement de page
Comme indiqué, lorsque vous passez d'une page jQuery Mobile à une autre, généralement en cliquant sur un lien vers une autre page jQuery Mobile qui existe déjà dans le DOM, ou en appelant manuellement $.mobile.changePage, plusieurs événements et actions subséquentes se produisent. À un haut niveau, 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é" (stylisé).
- Une transition (glissement/pop/etc) de la page existante à la nouvelle page se produit.
Il s'agit d'un repère de transition de page moyenne :
Chargement et traitement de la page : 3 ms
Améliorer la page : 45 ms
Transition : 604 ms
Temps total : 670 ms
*Ces valeurs sont en millisecondes.
Comme vous pouvez le constater, 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
Il est possible d'envoyer un ou plusieurs paramètres d'une page à l'autre lors d'une transition de page. Cela peut être fait de plusieurs 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 ceci :
$(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>
deuxième.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 :
Vous pouvez également créer un objet JavaScript persistant à des fins de stockage. Tant qu'Ajax est utilisé pour le chargement de la page (et que la page n'est pas rechargée de quelque manière que ce soit), 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'));
});
page précédente contient une page précédente complète.
Solution 4 :
Comme dernière solution, nous disposons d'une implémentation HTML astucieuse de localStorage. Elle ne fonctionne qu'avec les navigateurs HTML5 (y compris les navigateurs Android et iOS) mais toutes les données stockées sont persistantes lors du rafraîchissement de la page.
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 etleer pour me l'avoir rappelé) d'utiliser on/off pour la liaison/déliaison d'événements, live/die et bind/unbind sont dépréciés.
La méthode .live() de jQuery a été considérée comme une aubaine lorsqu'elle a été introduite dans l'API dans la version 1.3. Dans une application jQuery typique, il peut y avoir beaucoup de manipulation du DOM et il peut devenir très fastidieux d'accrocher et de décrocher les éléments qui vont et viennent. Le site .live()
permet d'accrocher un événement pour toute la durée de vie de l'application en fonction de son sélecteur. Super, non ? Faux, la méthode .live()
est extrêmement lente. Le site .live()
accroche en fait ses événements à l'objet document, ce qui signifie que l'événement doit remonter de l'élément qui l'a généré jusqu'à ce qu'il atteigne le document. Cela peut prendre énormément de temps.
Il est maintenant déprécié. Les membres 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 l'option .live()
qu'avec elle.
Au lieu de .live()
vous devez utiliser .on()
. .on()
est environ 2 à 3 fois plus rapide que .live() . Jetez un coup d'œil à ce repère de liaison d'événement : http://jsperf.com/jquery-live-vs-delegate-vs-on/34 tout sera clair à partir de là.
Benchmarking :
Il y a un excellent script fait pour jQuery Mobile page benchmarking des événements. 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, je vous conseille d'enlever son alert
système de notification (chaque "page de changement" va vous montrer ces données en arrêtant l'application) et changez-le en console.log
fonction.
Fondamentalement, ce script enregistrera tous vos événements de page et si vous lisez cet article attentivement (descriptions des événements de page) vous saurez combien de temps jQm a passé d'améliorations de page, de transitions de page .....
Notes finales
Toujours, et je dis bien toujours, lire les documents officiels jQuery Mobile la documentation. Elle vous fournira généralement les informations nécessaires, et contrairement à d'autres documentations, celle-ci est plutôt bonne, avec suffisamment d'explications et d'exemples de code.
Changements :
- 30.01.2013 - Ajout d'une nouvelle méthode de prévention du 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 nouveau contenu/exemples au chapitre Manipulation des données/paramètres entre les transitions de page
- 22.05.2013 - Ajout d'une solution pour la prévention de la transition/du changement de page et ajout de liens vers la documentation officielle de l'API des événements de page.
- 18.05.2013 - Ajout d'une autre solution contre la liaison d'événements multiples
0 votes
À la question 1, les deux sont identiques. Pouvez-vous les modifier ou expliquer un peu plus ce que vous voulez dire ?
0 votes
Ainsi, moins d'un an plus tard, concernant l'événement pageinit, "Cet événement a été déprécié dans la version 1.4.0 en faveur de pagecreate". Voir api.jquerymobile.com/pageinit