jQuery Mobile 1.4アップデート:
私の元の記事は、古い方法のページ処理、基本的にはjQueryMobile1.4より前のすべてを対象としていました。古い処理方法は廃止され、jQuery Mobile 1.5(を含む)までアクティブなままになるため、少なくとも来年とjQuery Mobile 1.6まで、以下に記載されているすべてのものを引き続き使用できます。
pageinitを含む古いイベントはもう存在せず、pagecontainerウィジェットに置き換えられます。Pageinitは完全に消去され、代わりにpagecreateを使用できます。そのイベントは同じままで、変更されません。
ページイベント処理の新しい方法に興味がある場合は、こちらをご覧ください。それ以外の場合は、この記事を続けてください。jQuery Mobile 1.4 +を使用している場合でも、この回答を読む必要があります。ページイベントを超えているため、多くの有用な情報が見つかる可能性があります。
古いコンテンツ:
この記事は、私のブログの一部としてここにあります。
$(document).on('pageinit')
vs$(document).ready()
jQueryで最初に学ぶことは、関数内でコードを呼び出し$(document).ready()
て、DOMが読み込まれるとすぐにすべてが実行されるようにすることです。ただし、jQuery Mobileでは、ナビゲートするときにAjaxを使用して各ページのコンテンツをDOMにロードします。このため$(document).ready()
、最初のページが読み込まれる前にトリガーされ、ページ操作を目的としたすべてのコードがページの更新後に実行されます。これは非常に微妙なバグである可能性があります。一部のシステムでは正常に動作しているように見える場合がありますが、他のシステムでは、不規則で、繰り返しの奇妙さを引き起こす可能性があります。
従来のjQuery構文:
$(document).ready(function() {
});
この問題を解決するために(そして私を信じてこれが問題である)、jQueryMobile開発者はページイベントを作成しました。一言で言えば、ページイベントは、ページ実行の特定のポイントでトリガーされるイベントです。これらのページイベントの1つはpageinitイベントであり、次のように使用できます。
$(document).on('pageinit', function() {
});
さらに進んで、ドキュメントセレクターの代わりにページIDを使用できます。IDインデックスを持つjQueryMobileページがあるとしましょう:
<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>
インデックスページでのみ使用できるコードを実行するには、次の構文を使用できます。
$('#index').on('pageinit', function() {
});
Pageinitイベントは、ページがロードされて初めて表示されるたびに実行されます。ページを手動で更新するか、Ajaxページの読み込みをオフにしない限り、再度トリガーされることはありません。ページにアクセスするたびにコードを実行する場合は、pagebeforeshowイベントを使用することをお勧めします。
実例を次に示します:http://jsfiddle.net/Gajotres/Q3Usv/この問題を示します。
この質問に関するメモはもう少しあります。1つのhtml複数ページまたは複数のHTMLファイルパラダイムを使用しているかどうかに関係なく、すべてのカスタムJavaScriptページ処理を単一の個別のJavaScriptファイルに分割することをお勧めします。これにより、コードがさらに改善されますが、特にjQuery Mobileアプリケーションを作成している間は、コードの概要が大幅に改善されます。
別の特別なjQueryMobileイベントもあり、 mobileinitと呼ばれます。jQuery Mobileが起動すると、ドキュメントオブジェクトでmobileinitイベントがトリガーされます。デフォルト設定を上書きするには、それらをmobileinitにバインドします。mobileinitの使用法の良い例の1つは、Ajaxページの読み込みをオフにするか、デフォルトのAjaxローダーの動作を変更することです。
$(document).on("mobileinit", function(){
//apply overrides here
});
ページイベントの遷移順序
まず、すべてのイベントはここで見つけることができます:http: //api.jquerymobile.com/category/events/
ページAとページBがあるとしましょう。これは、アンロード/ロードの順序です。
ページB-イベントpagebeforecreate
ページB-イベントpagecreate
ページB-イベントpageinit
ページA-イベントpagebeforehide
ページA-イベントpageremove
ページA-イベントページ非表示
ページB-イベントpagebeforeshow
ページB-イベントページショー
ページイベントの理解を深めるには、次をお読みください。
pagebeforeload
、pageload
およびpageloadfailed
外部ページがロードされたときに発生します
pagebeforechange
、pagechange
およびpagechangefailed
はページ変更イベントです。これらのイベントは、ユーザーがアプリケーションのページ間を移動しているときに発生します。
pagebeforeshow
、、pagebeforehide
およびpageshow
はpagehide
ページ遷移イベントです。これらのイベントは、移行前、移行中、移行後に発生し、名前が付けられます。
pagebeforecreate
、pagecreate
およびpageinit
はページの初期化用です。
pageremove
ページがDOMから削除されたときに起動して処理できます
ページの読み込みjsFiddleの例:http ://jsfiddle.net/Gajotres/QGnft/
AJAXが有効になっていない場合、一部のイベントが発生しない可能性があります。
ページ遷移を防ぐ
何らかの理由でページ遷移を何らかの条件で防止する必要がある場合は、次のコードで実行できます。
$(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');;
}
}
});
この例は、すべてのページ遷移の開始時にトリガーされ、最も重要なことは、ページ遷移が発生する前にページ変更を防ぐため、どのような場合でも機能します。
実例は次のとおりです。
複数のイベントのバインド/トリガーを防止する
jQuery Mobile
従来のWebアプリケーションとは異なる方法で機能します。あるページにアクセスするたびにイベントをバインドする方法に応じて、イベントは何度もバインドされます。これはエラーではなく、単にjQuery Mobile
そのページを処理する方法です。たとえば、次のコードスニペットを見てください。
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
動作するjsFiddleの例:http ://jsfiddle.net/Gajotres/CCfL4/
ページにアクセスするたびに、# indexクリックイベントがボタン#test-buttonにバインドされます。1ページから2ページに移動し、数回戻ってテストします。この問題を防ぐ方法はいくつかあります。
解決策1
最善の解決策はpageinit
、イベントのバインドに使用することです。pageinit
公式ドキュメントを見ると、ドキュメントの準備ができているのと同じように、一度だけトリガーされることがわかります。したがって、イベントが再びバインドされることはありません。offメソッドでイベントを削除する場合のように処理のオーバーヘッドがないため、これが最適なソリューションです。
動作するjsFiddleの例:http ://jsfiddle.net/Gajotres/AAFH8/
この実用的なソリューションは、以前の問題のある例に基づいて作成されています。
解決策2
バインドする前にイベントを削除します。
$(document).on('pagebeforeshow', '#index', function(){
$(document).off('click', '#test-button').on('click', '#test-button',function(e) {
alert('Button click');
});
});
動作するjsFiddleの例:http ://jsfiddle.net/Gajotres/K8YmG/
解決策3
次のようなjQueryフィルターセレクターを使用します。
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
イベントフィルターは公式のjQueryフレームワークの一部ではないため、次の場所にあります: http: //www.codenothing.com/archives/2009/event-filter/
一言で言えば、速度が主な関心事である場合、ソリューション2はソリューション1よりもはるかに優れています。
解決策4
新しいもの、おそらくそれらすべての中で最も簡単です。
$(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;
}
});
});
動作するjsFiddleの例:http ://jsfiddle.net/Gajotres/Yerv9/
このソリューションのsholsingerへのTnx : http ://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
pageChangeイベントの癖-2回トリガー
pagechangeイベントが2回トリガーされることがあり、前述の問題とは何の関係もありません。
pagebeforechangeイベントが2回発生する理由は、toPageがjQuery拡張DOMオブジェクトでない場合にchangePageが再帰的に呼び出されるためです。開発者はイベント内でtoPageを変更できるため、この再帰は危険です。開発者が一貫してtoPageを文字列に設定すると、それがオブジェクトであるかどうかに関係なく、pagebeforechangeイベントハンドラー内で、無限の再帰ループが発生します。pageloadイベントは、新しいページをデータオブジェクトのページプロパティとして渡します(これはドキュメントに追加する必要があります。現在はリストされていません)。したがって、pageloadイベントを使用して、ロードされたページにアクセスできます。
簡単に言うと、これはpageChangeを介して追加のパラメーターを送信しているために発生しています。
例:
<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>
この問題を修正するには、ページイベントの遷移順序にリストされているページイベントを使用します。
ページ変更時間
前述のように、あるjQuery Mobileページから別のページに変更すると、通常はDOMに既に存在する別のjQuery Mobileページへのリンクをクリックするか、手動で$ .mobile.changePageを呼び出すことにより、いくつかのイベントと後続のアクションが発生します。大まかに言うと、次のアクションが発生します。
- ページ変更プロセスが開始されます
- 新しいページが読み込まれます
- そのページのコンテンツは「拡張」(スタイル設定)されています
- 既存のページから新しいページへの遷移(スライド/ポップなど)が発生します
これは平均的なページ遷移ベンチマークです。
ページの読み込みと処理:3ミリ秒
ページエンハンス:45ミリ秒
遷移:604ミリ秒
合計時間:670ミリ秒
*これらの値はミリ秒単位です。
ご覧のとおり、移行イベントは実行時間のほぼ90%を消費しています。
ページ遷移間のデータ/パラメータ操作
ページ遷移中に、あるページから別のページにパラメータを送信することができます。それはいくつかの方法で行うことができます。
参照:https ://stackoverflow.com/a/13932240/1848600
解決策1:
changePageを使用して値を渡すことができます。
$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });
そして、このようにそれらを読んでください:
$(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>
解決策2:解決策2:
または、保存目的で永続的なJavaScriptオブジェクトを作成することもできます。Ajaxがページのロードに使用されている限り(そしてページがリロードされていない限り)、そのオブジェクトはアクティブなままです。
var storeObject = {
firstname : '',
lastname : ''
}
例: http: //jsfiddle.net/Gajotres/9KKbx/
解決策3:
次のように、前のページのデータにアクセスすることもできます。
$(document).on('pagebeforeshow', '#index',function (e, data) {
alert(data.prevPage.attr('id'));
});
prevPageオブジェクトは、完全な前のページを保持します。
解決策4:
最後の解決策として、localStorageの気の利いたHTML実装があります。HTML5ブラウザ(AndroidおよびiOSブラウザを含む)でのみ機能しますが、保存されているすべてのデータはページの更新を通じて保持されます。
if(typeof(Storage)!=="undefined") {
localStorage.firstname="Dragan";
localStorage.lastname="Gaic";
}
例: http: //jsfiddle.net/Gajotres/J9NTr/
おそらく最良の解決策ですが、iOS5.Xの一部のバージョンでは失敗します。よく知られているエラーです。
使用しないでください.live()
//.bind()
.delegate()
イベントのバインド/バインド解除、ライブ/ダイ、バインド/アンバインドのオン/オフの使用は非推奨です。
jQueryの.live()メソッドは、バージョン1.3でAPIに導入されたとき、天の恵みと見なされていました。典型的なjQueryアプリでは、多くのDOM操作が行われる可能性があり、要素が行き来するときにフックとフックを解除するのは非常に面倒になる可能性があります。この.live()
メソッドにより、セレクターに基づいて、アプリの存続期間中イベントをフックすることが可能になりました。いいですね?間違って、.live()
方法は非常に遅いです。この.live()
メソッドは、実際にはそのイベントをドキュメントオブジェクトにフックします。つまり、イベントは、イベントを生成した要素からドキュメントに到達するまでバブルアップする必要があります。これは驚くほど時間がかかる可能性があります。
現在は非推奨です。jQueryチームの人々は、もはやその使用を推奨していませんし、私も推奨していません。イベントをフックおよびフック解除するのは面倒ですが、メソッドを使用しない場合は、.live()
メソッドを使用する場合よりもコードがはるかに高速になります。
代わりに.live()
を使用する必要があります.on()
。.live().on()
よりも約2〜3倍高速です。このイベントバインディングベンチマークを見てください:http://jsperf.com/jquery-live-vs-delegate-vs-on/34、そこからすべてが明らかになります。
ベンチマーク:
jQueryMobileページイベントのベンチマーク用に作成された優れたスクリプトがあります。ここで見つけることができます:https ://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js 。ただし、何かを行う前に、alert
通知システムを削除して(各「変更ページ」でアプリを停止することでこのデータが表示されます)、console.log
機能するように変更することをお勧めします。
基本的に、このスクリプトはすべてのページイベントをログに記録します。この記事(ページイベントの説明)を注意深く読むと、jQmがページの拡張やページの遷移に費やした時間を知ることができます。
最終メモ
常に、つまり常に公式のjQueryMobileドキュメントを読むことを意味します。通常、必要な情報を提供します。他のドキュメントとは異なり、これはかなり優れており、十分な説明とコード例があります。
変更点:
- 30.01.2013-複数のイベントトリガー防止の新しい方法を追加しました
- 31.01.2013-ページ遷移間のデータ/パラメーター操作の章のより良い説明を追加しました
- 2013年2月3日-ページ遷移間のデータ/パラメータ操作の章に新しいコンテンツ/例を追加しました
- 2013年5月22日-ページ遷移/変更防止のソリューションを追加し、公式ページイベントAPIドキュメントへのリンクを追加しました
- 18.05.2013-複数のイベントのバインドに対する別のソリューションを追加しました