1. ホーム
  2. ジャバスクリプト

[解決済み】jQuery Mobile: ドキュメントレディとページイベントの比較

2022-04-19 20:43:21

質問

jQuery Mobileを使用していますが、古典的なdocument readyとjQuery Mobileのpageイベントの違いがわからず困っています。

  1. 本当の違いは何ですか?

    なぜ

    <!-- language: lang-js -->
    
    $(document).ready() {
    
    });
    
    

    上回る

    $(document).on('pageinit') {
    
    });
    
    
  2. あるページから別のページに遷移する際の、ページイベントの順番を教えてください。

  3. あるページから別のページにデータを送信する方法と、前のページのデータにアクセスすることは可能ですか?

どのように解決するのですか?

jQuery Mobile 1.4 アップデート。

私の元の記事は、古いページ処理方法、基本的にjQuery Mobile 1.4以前のすべてのものを対象としていました。古い処理方法は現在非推奨となっており、jQuery Mobile 1.5まで(を含む)有効であるため、少なくとも来年とjQuery Mobile 1.6までは、以下に述べるすべてのものを使用できます。

などの旧イベント ページ編集 はもう存在しないので、代わりに ページコンテナ ウィジェットを使用します。 ページニット は完全に消去され ページクリエイト このイベントは変更されることはありません。

もし、ページイベントの新しい処理方法に興味があれば、以下をご覧ください。 こちら その他の場合は、この記事を読み進めてください。jQuery Mobile 1.4 +を使用している場合でも、この回答を読む必要があります。

古いコンテンツです。

この記事は、私のブログの一部としても見ることができます。 こちら .

$(document).on('pageinit')$(document).ready()

で最初に学ぶことは jQuery の中のコードを呼び出すことです。 $(document).ready() 関数を使用すると、DOM がロードされると同時にすべてが実行されます。しかし jQueryモバイル Ajaxは、各ページのコンテンツを移動しながらDOMに読み込むために使用されます。このため $(document).ready() は最初のページがロードされる前に起動され、ページ操作を目的としたすべてのコードはページ更新後に実行されます。これは非常に微妙なバグである可能性があります。あるシステムでは問題なく動作しているように見えますが、別のシステムでは、不規則で再現が困難な奇妙な現象が発生することがあります。

古典的なjQueryの構文です。

$(document).ready(function() {

});

この問題を解決するために(そして、これは問題であると私を信じてください) jQuery Mobile の開発者は、ページイベントを作成しました。簡単に言うと、ページイベントはページ実行の特定のポイントでトリガーされるイベントです。そのページイベントのひとつが ページ編集 というイベントがあり、このような使い方ができます。

$(document).on('pageinit', function() {

});

さらに進んで、ドキュメントセレクタの代わりにページ ID を使用することもできます。例えば、jQuery Mobileのページで、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>

インデックス・ページでのみ利用可能なコードを実行するには、次の構文を使用します。

$('#index').on('pageinit', function() {

});

ページニット イベントは、ページが読み込まれて初めて表示されるたびに実行されます。このイベントは、ページが手動で更新されるか、Ajaxによるページの読み込みがオフにされない限り、再び実行されることはありません。ページにアクセスするたびにコードを実行させたい場合には ページビフォアショー イベントを使用します。

以下は動作例です。 http://jsfiddle.net/Gajotres/Q3Usv/ を使用して、この問題を実証します。

この質問について、もう少しだけ注意点があります。1つのHTMLを複数のページや複数のHTMLファイルで使用している場合でも、カスタムJavaScriptのページ処理をすべて1つの独立したJavaScriptファイルに分離することをお勧めします。これはあなたのコードをより良くするものではありませんが、あなたはより良いコードの概要を持つことができます。 jQueryモバイル アプリケーションを作成することができます。

また、もう1つの特別な jQueryモバイル イベントと呼ばれるもので モバイルイナ . いつ jQuery Mobile が開始されると、それがトリガーとなって モバイルイナット イベントが発生します。デフォルトの設定をオーバーライドするには、その設定を モバイルイニット . の良い例の1つは モバイルイット の使用法は、Ajaxページの読み込みをオフにしたり、Ajaxローダーのデフォルトの動作を変更したりすることです。

$(document).on("mobileinit", function(){
  //apply overrides here
});

ページイベントの遷移順序

最初にすべてのイベントをここで見ることができます。 http://api.jquerymobile.com/category/events/

ページAとページBがあり、これはアンロードとロードの順序です。

  1. ページB - イベント ページビフォークリエイト

  2. Bページ - イベント ページクリエイト

  3. Bページ - イベント ページニット

  4. ページ A - イベント ページビフォアハイド

  5. ページ A - イベント ページ削除

  6. ページ A - イベント ページハイド

  7. Bページ - イベント ページビフォアショー

  8. 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 は、古典的なウェブアプリケーションとは異なる方法で動作します。イベントをどのようにバインドしたかによりますが、あるページにアクセスするたびに、何度もイベントがバインドされることになります。これはエラーではありません。 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/

ページにアクセスするたびに #インデックス クリックイベントがボタンにバインドされます。 #test-button . 1ページ目から2ページ目へ何度か移動してテストしてください。この問題を防ぐ方法はあまりありません。

解決策1

最適な解決策は pageinit を使用してイベントをバインドします。公式のドキュメントを見れば、以下のことがわかるでしょう。 pageinit は、document ready と同じように一度だけ起動するので、イベントが再びバインドされることはありません。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/

Tnx to the ショルジンガー この解決策に http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/

pageChangeイベントのクセ - 2回トリガーされる

ページチェンジイベントが2回発生することがありますが、前述の問題とは関係ありません。

pagebeforechange イベントが 2 回発生する理由は、toPage が jQuery 拡張 DOM オブジェクトでない場合に changePage で再帰的な呼び出しが行われるためです。この再帰呼び出しは危険で、開発者はイベント内でtoPageを変更することが許されているからです。開発者が pagebeforechange イベントハンドラ内で toPage を一貫して文字列に設定すると、それがオブジェクトであるかどうかにかかわらず、無限再帰ループが発生します。pageload イベントは、データオブジェクトの page プロパティとして新しいページを渡します (これはドキュメントに追加されるべきです。現在は記載されていません)。したがって、pageload イベントは、読み込まれたページにアクセスするために使用することができます。

簡単に言うと、これはpageChangeを通して追加のパラメータを送信しているために起こっているのです。

<a data-role="button" data-icon="arrow-r" data-iconpos="right" href="#care-plan-view?id=9e273f31-2672-47fd-9baa-6c35f093a800&amp;name=Sat"><h3>Sat</h3></a>

この問題を解決するためには ページイベントの遷移順 .

ページ切り替え時間

前述のとおり、あるjQuery Mobileページから別の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.

または、保存用に永続的なJavaScriptオブジェクトを作成することができます。ページの読み込みにAjaxが使用されている限り(そして、ページが何らかの方法で再読み込みされない限り)、そのオブジェクトはアクティブなままです。

var storeObject = {
    firstname : '',
    lastname : ''
}

http://jsfiddle.net/Gajotres/9KKbx/

解決策3.

また、このように前のページのデータにアクセスすることもできます。

$(document).on('pagebeforeshow', '#index',function (e, data) {
    alert(data.prevPage.attr('id'));
});

プレページ オブジェクトは、完全な前ページを保持します。

解決策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 アンドレアー イベントのバインド/アンバインドにはon/offを使用し、live/dieとbind/unbindは非推奨です。

jQueryの.live()メソッドは、バージョン1.3でAPIに導入されたとき、天の恵みと見なされていました。典型的なjQueryアプリではDOM操作が多く、要素の出入りに応じてフックをかけたり外したりするのが非常に面倒になる場合があります。そのため .live() メソッドによって、セレクタに基づいたイベントをアプリの全期間にわたってフックすることが可能になりました。素晴らしいでしょう?そうではありません。 .live() メソッドは非常に遅いです。その .live() つまり、イベントを発生させた要素から document に到達するまで、イベントをバブルアップさせなければなりません。これは驚くほど時間がかかることでしょう。

現在では非推奨となっています。イベントのフックとアンフックを行うのは面倒ですが、このメソッドを使用しない方がコードはずっと速くなります。 .live() メソッドがある場合よりも

の代わりに .live() を使用する必要があります。 .on() . .on() は、2-3倍程度速くなります。 .live() . このイベントバインディングのベンチマークを見てみましょう。 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 のドキュメントを参照してください。他のドキュメントとは異なり、十分な説明とコード例があり、むしろ良いものです。

変更点

  • 2013.01.30 - 複数イベントのトリガー防止方法を追加しました。
  • 2013.01.31 - チャプターの説明をより明確にしました。 ページ遷移間のデータ/パラメータ操作について
  • 2013.02.03 - この章に新しいコンテンツ/サンプルを追加しました。 ページ遷移間のデータ/パラメータ操作
  • 2013.05.22 - ページ遷移/変更防止のためのソリューションを追加し、公式ページイベントAPIドキュメントへのリンクを追加しました。
  • 2013.05.18 - 複数イベントバインディングに対する別の解決策を追加しました。