web-dev-qa-db-ja.com

jQuery Mobile:文書準備完了イベントとページイベント

私はjQuery Mobileを使用しています、そして私は古典的なdocument readyとjQuery Mobileページイベントの違いを理解するのに苦労しています。

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

    どうして〜しなきゃいけない

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

    より良くなる

    $(document).on('pageinit') {
    
    });
    
  2. あるページから別のページに移動したときのページイベントの順序は何ですか?

  3. あるページから別のページにデータを送信するにはどうすればよいですか。また、前のページのデータにアクセスすることは可能ですか?

260
user2001897

jQuery Mobile 1.4アップデート:

私の最初の記事は、古い方法のページ処理、基本的にはjQuery Mobile 1.4より前のすべてを対象としていました。古い取り扱い方法は現在は推奨されておらず、jQuery Mobile 1.5まで(それを含む)アクティブであり続けるので、少なくとも来年とjQuery Mobile 1.6までは、以下に記載されているすべてのものを使用できます。

pageinitを含む古いイベントはもう存在しません。pagecontainerウィジェットに置き換えられます。 Pageinitは完全に消去され、代わりにpagecreateを使用することができます。その場合、そのイベントは同じままで変更されません。

あなたがページイベント処理の新しい方法に興味を持っているならば、他の場合にはここで見てくださいこの記事を続けてください。 jQuery Mobile 1.4以降を使用している場合でもこの回答を読む必要があります。これはページイベントを超えたものであるため、おそらく有用な情報がたくさんあります。

古いコンテンツ:

この記事は私のブログの一部としても見られますHERE

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

jQueryで最初に学ぶことは、$(document).ready()関数内のコードを呼び出すことです。そうすれば、DOMがロードされるとすぐにすべてが実行されます。 。ただし、jQuery Mobileでは、ナビゲートしながらAjaxを使用して各ページのコンテンツをDOMにロードします。このため$(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ページ処理を単一の別々の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があるとしましょう。これはアンロード/ロードの順序です。

  1. ページB - イベントpagebeforecreate

  2. ページB - イベントpagecreate

  3. ページB - イベントpageinit

  4. ページA - イベントpagebeforehide

  5. ページA - イベントpageremove

  6. ページA - イベントpagehide

  7. ページB - イベントpagebeforeshow

  8. ページB - イベントpageshow

より良いページイベント理解のためにこれを読んでください:

  • pagebeforeloadpageloadpageloadfailedは外部ページがロードされたときに発生します
  • pagebeforechangepagechange、およびpagechangefailedはページ変更イベントです。これらのイベントは、ユーザーがアプリケーション内のページ間を移動しているときに発生します。
  • pagebeforeshowpagebeforehidepageshowおよびpagehideはページ遷移イベントです。これらのイベントは、遷移の前、最中、後に発生し、名前が付けられます。
  • pagebeforecreatepagecreatepageinitは、ページの初期設定用です。
  • 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クリックイベントはbutton#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/

一言で言えば、もし速度があなたの主な関心事であるならば、Solution 2はSolution 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-handler-from-multiple-times /

pageChangeイベントが奇妙になる - 2回トリガーする

ときどきpagechangeイベントが2回発生することがあり、それは前述の問題とは無関係です。

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

簡単に言うと、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>

この問題を解決するには、ページイベント遷移順にリストされている任意のページイベントを使用します。

ページ変更時間

前述のように、あるDOMクエリーページから別のページに切り替えると、通常はDOM内に既に存在する別のjQuery Mobileページへのリンクをクリックするか、手動で$ .mobile.changePageを呼び出すことによって変更されます。高レベルでは、次のことが起こります。

  • ページ変更プロセスが開始されました
  • 新しいページがロードされました
  • そのページのコンテンツは「拡張」(スタイル)されています
  • 既存のページから新しいページへの移行(slide/pop/etc)が発生します

これは平均的なページ遷移のベンチマークです。

ページの読み込みと処理: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'));
});

prevPageオブジェクトは前のページ全体を保持します。

解決策4:

最後の解決策として、localStorageの気の利いたHTML実装があります。これはHTML 5ブラウザ(AndroidおよびiOSブラウザを含む)でのみ機能しますが、保存されているすべてのデータはページを更新しても保持されます。

if(typeof(Storage)!=="undefined") {
    localStorage.firstname="Dragan";
    localStorage.lastname="Gaic";
}

例: http://jsfiddle.net/Gajotres/J9NTr/

おそらく最善の解決策ですが、iOS 5.Xの一部のバージョンでは失敗します。それはよく知られた誤りです。

.live()/.bind()/.delegate()を使用しない

イベントのバインド/アンバインドにon/offを使用すること、およびライブ/ダイ、バインド/アンバインドは廃止される予定です(そしてtnx andleer を使用することを忘れていました)。

JQueryの.live()メソッドは、バージョン1.3でAPIに導入されたときにはゴッドエンドと見なされていました。典型的なjQueryアプリではDOM操作がたくさんあり、要素が出たり入ったりするときにフックしたり外したりするのはとても面倒です。 .live()メソッドは、そのセレクターに基づいてアプリの寿命の間イベントをフックすることを可能にしました。いいですか?間違った、.live()メソッドは非常に遅いです。 .live()メソッドは、実際にはイベントをドキュメントオブジェクトにフックします。つまり、イベントは、イベントを生成した要素からドキュメントに到達するまでバブルアップする必要があります。これは驚くほど時間がかかります。

現在は非推奨です。 jQueryチームの人々はもはやその使用を推奨せず、またIも行いません。イベントをフックしたりフック解除したりするのは面倒なことになるかもしれませんが、.live()メソッドを使用しない方がはるかに速くなります。

.live()の代わりに、.on()を使用してください。 .on()は、。live()よりも約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 - ページ遷移間の章データ/パラメータ操作に関するより明確な説明を追加しました
  • 03.02.2013 - 章に新しい内容/例を追加しましたページ遷移間のデータ/パラメータ操作
  • 22.05.2013 - ページ遷移/変更防止のためのソリューションを追加し、公式ページイベントAPIドキュメントへのリンクを追加しました
  • 18.05.2013 - マルチイベントバインディングに対する別の解決策を追加しました
438
Gajotres

あなたの中にはこれが役に立つと思うかもしれません。コピーしてページに貼り付けるだけで、Chromeコンソールでイベントが発生するシーケンスが表示されます(Ctrl + Shift + I).

$(document).on('pagebeforecreate',function(){console.log('pagebeforecreate');});
$(document).on('pagecreate',function(){console.log('pagecreate');});
$(document).on('pageinit',function(){console.log('pageinit');});
$(document).on('pagebeforehide',function(){console.log('pagebeforehide');});
$(document).on('pagebeforeshow',function(){console.log('pagebeforeshow');});
$(document).on('pageremove',function(){console.log('pageremove');});
$(document).on('pageshow',function(){console.log('pageshow');});
$(document).on('pagehide',function(){console.log('pagehide');});
$(window).load(function () {console.log("window loaded");});
$(window).unload(function () {console.log("window unloaded");});
$(function () {console.log('document ready');});

ページがアンロードされているとき(ページから移動したとき)にコンソールがアンロードされるため、コンソールでアンロードされることはありません。このように使用してください。

$(window).unload(function () { debugger; console.log("window unloaded");});

そして、あなたは私が何を言っているのかわかるでしょう。

17

これは正しい方法です。

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

$(document).on('pageinit', "#index",  function() {
    ...
});
3
kecco

JQuery-mobileのdocument readyとpageイベントの単純な違いは、次のとおりです。

  1. Document readyイベントはHTMLページ全体に使用されます。

    $(document).ready(function(e) {
        // Your code
    });
    
  2. ページイベントがある場合は、特定のページイベントを処理するために使用します。

    <div data-role="page" id="second">
        <div data-role="header">
            <h3>
                Page header
            </h3>
        </div>
        <div data-role="content">
            Page content
        </div> <!--content-->
        <div data-role="footer">
            Page footer
        </div> <!--footer-->
    </div><!--page-->
    

Pageinitイベントを処理するためにdocumentを使うこともできます。

$(document).on('pageinit', "#mypage", function() {

});
1
LeoMobDev