jQuery Mobile 1.4アップデート:
私の元の記事は、ページ処理の古い方法、つまりjQuery Mobile 1.4より前のすべてを対象としています。古い処理方法は非推奨になり、jQuery Mobile 1.5(含む)までアクティブのままになるため、少なくとも翌年とjQuery Mobile 1.6までは、以下で説明するすべてを引き続き使用できます。
pageinitを含む古いイベントはもう存在せず、pagecontainerウィジェットに置き換えられています。Pageinitは完全に消去され、代わりにpagecreateを使用できます。そのイベントは同じままで、変更されません。
ページイベント処理の新しい方法に興味がある場合は、こちらをご覧ください。それ以外の場合は、この記事を続けてください。jQuery Mobile 1.4以降を使用している場合でも、この回答を読む必要があります。これはページイベントを超えているため、おそらく多くの有用な情報を見つけることができます。
古いコンテンツ:
この記事は私のブログの一部としてもここにあります。
$(document).on('pageinit')
対 $(document).ready()
jQueryで最初に学ぶことは$(document).ready()
、DOMがロードされるとすぐにすべてが実行されるように、関数内のコードを呼び出すことです。ただし、jQuery Mobileでは、ナビゲート時に各ページのコンテンツをDOMにロードするためにAjaxが使用されます。このため$(document).ready()
、最初のページがロードされる前にトリガーされ、ページ操作を目的としたすべてのコードがページの更新後に実行されます。これは非常に微妙なバグになる可能性があります。一部のシステムでは正常に動作しているように見えるかもしれませんが、他のシステムでは奇妙で繰り返しが難しい奇妙な現象が発生する可能性があります。
クラシックjQuery構文:
$(document).ready(function() {
});
この問題を解決するために(そしてこれが問題であると信じて)、jQuery Mobile開発者がページイベントを作成しました。簡単に言うと、ページイベントは、ページ実行の特定のポイントでトリガーされるイベントです。それらのページイベントの1つはpageinitイベントであり、次のように使用できます。
$(document).on('pageinit', function() {
});
さらに進んで、ドキュメントセレクターの代わりにページIDを使用できます。id インデックスを持つjQuery Mobileページがあるとします。
<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ページ処理を1つの個別のJavaScriptファイルに分離することをお勧めします。これにより、コードが改善されますが、特にjQuery Mobileアプリケーションを作成している間は、コードの概要が大幅に改善されます。
別の特別なjQuery Mobileイベントもあり、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イベントは、新しいページをデータオブジェクトのページプロパティとして渡します(これはドキュメントに追加する必要があります。現在、リストには含まれていません)。したがって、ページロードイベントを使用して、ロードされたページにアクセスできます。
簡単に言うと、これは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 ms
遷移:604ミリ秒
合計時間:670 ms
*これらの値はミリ秒単位です。
ご覧のとおり、遷移イベントは実行時間のほぼ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:
または、保存目的で永続的な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/
おそらく最良の解決策ですが、iOS 5.Xの一部のバージョンでは失敗します。これはよく知られたエラーです。
使用しないでください.live()
/ .bind()
/.delegate()
私は(とTNX言及するのを忘れてしまったandleerイベントのオン/オフを使用/アンバインド、ライブ/ダイとバインドを結合/アンバインド私を思い出させるために)廃止されました。
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、そこからすべてが明確になります。
ベンチマーク:
jQuery Mobileページイベントのベンチマーク用に作成された優れたスクリプトがあります。これは、https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.jsにあります。しかし、何かをする前に、そのalert
通知システムを削除し(各「変更ページ」がアプリを停止することでこのデータを表示する)、それをconsole.log
機能するように変更することをお勧めします。
基本的に、このスクリプトはすべてのページイベントをログに記録し、この記事(ページイベントの説明)を注意深く読むと、jQmがページ拡張、ページ遷移などに費やした時間を知ることができます。
最終メモ
常に、そして私は常に公式のjQuery Mobileドキュメントを読むことを意味します。通常、必要な情報を提供します。他のいくつかのドキュメントとは異なり、十分な説明とコード例があり、これはかなり良いドキュメントです。
変更:
- 30.01.2013-複数のイベントトリガー防止の新しい方法を追加
- 31.01.2013- ページ遷移間のデータ/パラメーター操作の章の明確化を追加
- 2013年2月3日- ページ遷移間のデータ/パラメータ操作の章に新しいコンテンツ/例を追加
- 2013年5月22日-ページ遷移/変更防止のソリューションを追加し、公式ページイベントAPIドキュメントへのリンクを追加
- 18.05.2013-複数のイベントバインディングに対する別のソリューションを追加しました