連載:jQuery Mobile入門(最終回)

第6回 jQuery Mobile APIでもっとJavaScriptプログラミング

山田 祥寛
2012/06/14
Page1 Page2

jQuery Mobile APIでカンタン・アプリ開発

 後半では、$.mobileオブジェクトで提供されるメソッド/プロパティを利用して、カンタンなスマホ・アプリを作成していく。$.mobileオブジェクトはjQuery Mobileのコアともいうべきオブジェクトのこと。個別のウィジェットだけでなく、$.mobileオブジェクトを理解することで、より細かなページ遷移やエフェクト、スクロールなどの制御が、アプリから可能になるだろう。

ページの先頭に戻るためのボタンを設置する ― silentScrollメソッド

 一般的なページでは、<a href="#">要素は、ページ先頭へのリンクを意味する。だが、jQuery Mobileでは、<a href="#">要素は「何も動作しないリンク」を意味するので、要注意だ(つまり、ページ先頭にも移動しない)。jQuery Mobileでは、JavaScriptによる処理を伴うようなリンク(ボタン)を生成するために、<a href="#">要素を予約しているのだ。

 本来、スマホ・アプリではスクロールによる上下の行き来を伴うような縦長のページを設けるよりも、ページを短く区切る方が望ましい。しかし、もしそのような操作を実装したい場合には、以下のようなコードを書かなければならない。

<div id="list" data-role="page" data-title="jQuery Mobile">
  <div data-role="header">
    <h1>jQuery Mobile</h1>
  </div>
  <div data-role="content">
    <p>ページ・イベントの中でも、特によく利用するのがpageinit...</p>
    <a class="top" href="#" data-role="button">トップへ</a>
  </div>
  <div data-role="footer">
    Copyright 1998-2012, WINGS Project
  </div>
</div>
$('.top').live('click', function() {
  $.mobile.silentScroll();
});
ボタン・クリックでページ先頭に戻るコード(上:silent.html/下:silent.js)

[トップへ]ボタンをタップ
[トップへ]ボタンのタップでページ先頭に移動

 silentScrollメソッドは、もともと引数で指定されたY座標まで、ページをスクロールするためのメソッドだ。引数の省略時は「0」と見なされる。よって、サンプルの太字部分は「$.mobile.silectScroll(0);」と書いても同じ意味となる。

スワイプ操作で前後ページに遷移する ― changePageメソッド

 前後で連続性を持つような一連のページを見せる場合、ボタンやリンクのタップで移動するよりも、スワイプ操作の方が本をめくる感が演出でき、直感的だ。

 ここでは、左右スワイプによって、before.html⇔current.html⇔after.htmlと前後ページに行き来する例を見てみよう。なお、before.htmlより前に戻ろうとするとafter.htmlに、after.htmlよりも後ろに行こうとするとbefore.htmlに、と前後循環するように遷移するものとする。

<div id="current" data-role="page" data-title="jQuery Mobile">
  <div data-role="header">
    <h1>jQuery Mobile</h1>jQuery Mobile

ページbeforeです。
  </div>
  <div data-role="content">
    ページcurrentです。
  </div>
  <div data-role="footer">
    Copyright 1998-2012, WINGS Project
  </div>
</div>
var current;  // 現在表示中のページ(インデックス番号)
var pages = ['before', 'current', 'after'];  // (1)ページのリスト

// (2)ページ遷移時に、現在のページ(インデックス番号)を取得
$(document).bind('pagechange', function(e, d) {
  current = pages.indexOf(d.toPage.attr('id'));
});

// (3)左スワイプ時に次ページに移動
$(':jqmData(role="page")').live('swipeleft', function(){
  if (current === pages.length - 1) {
    var path = pages[0] + '.html';
  } else {
    var path = pages[current + 1] + '.html';
  }
  $.mobile.changePage(path, { transition : 'slide' });
});

// (4)右スワイプ時に前ページ移動
$(':jqmData(role="page")').live('swiperight', function(){
  if (current === 0) {
    var path = pages[pages.length - 1] + '.html';
  } else {
    var path = pages[current - 1] + '.html';
  }
  $.mobile.changePage(path, { transition : 'slide', reverse: true });
});
スワイプ時に前後ページに移動するコード(上:current.html、下:current.js)
before.html/after.htmlも太字の部分がそれぞれ「before」や「after」に置き換わるだけで内容は同じ。

 やや複雑なコードなので、順番に処理の流れを追っていこう。

(1)ページの前後関係を配列で宣言

 まずは、ページの前後関係を配列「pages」で宣言しておこう。サンプルであれば、before.html→current.html→after.htmlという関係を表している。

 なお、このサンプルでは、ページのベース名(=ファイル名から拡張子を取り除いたもの)とページ要素のid値とが等しいことを前提としている。例えば、current.htmlのページidは「current」でなければならない*4

*4 ファイル名とid値の管理をシンプルにするという意味では、このサンプルに限らず、ベース名とページidに対応関係を持たせておくのは良い習慣だ。

(2)ページ遷移時に、現在のページのインデックス番号を保存

 (2)では、ページ遷移のタイミングで、現在ページのインデックス番号を保存している。これは、後からページを遷移する際に、前後ページを検索する基点とするためだ。

 indexOfメソッドは、指定の要素が配列の何番目に登場するかを検索するためのメソッドだ。「d.toPage.attr('id')」は、遷移後のページidを意味する*5。よって、「pages.indexOf(d.toPage.attr('id'))」で、「遷移後のページが配列pagesの何番目の要素であるか」を取り出しているわけだ。

*5 ページ・イベントでは、データ・オブジェクトを介して、ページに関わる情報にアクセスできるのだった。

(3)左スワイプで次ページに遷移する

 遷移先を決めているのは、ifブロックだ。条件式「current === pages.length - 1」は、現在のページ(current)がページ・リスト(pages)の末尾であるかを判定している。現在のページがリストの末尾であれば、先頭ページ(pages[0])を遷移先に、さもなければ、次のページ(pages[current + 1])を遷移先に設定しているわけだ。

 遷移先が決まってしまえば、後はページの遷移処理を実行するだけだ。ページ遷移には、$.mobile.changePageメソッド(使い方は以下を参照)を呼び出せばよい。

$.mobile.changePage(url [, opts])
[構文]$.mobile.changePageメソッド
ページ遷移する。
url:遷移先のページ。
opts:遷移オプション。

オプション名 概要 デフォルト値
allowSamePageTransition 同じページへの遷移を許可するか false
data URLに付与するクエリ情報  
reloadPage 遷移先ページが文書ツリー上にあっても再読み込みするか false
reverse 遷移エフェクトを逆方向に再生するか false
showLoadMsg ローディング・メッセージを表示するか true
transition 遷移エフェクト $.mobile.defaultPageTransition
type リクエスト時に使用するHTTPメソッド(get|post) get
changePageメソッドの主な遷移オプション

 なお、JavaScript標準のlocation.hrefプロパティでは、遷移エフェクトやローディング・メッセージなどは適用されないので注意してほしい。

(4)左スワイプで前ページに遷移する

 右スワイプの場合も、遷移先を決めて、changePageメソッドでページを移動するという流れは同じだ。ただし、遷移先の決定ルールが(3)とは異なる。右スワイプでは、現在ページがリストの先頭である(current === 0)場合には、末尾ページ(pages[pages.length - 1])を遷移先に、さもなければ、前のページ(pages[current - 1])を遷移先に設定している。

 また、changePageメソッドで、reverseオプションを指定している点にも注目だ。前ページに戻る場合は、slide効果も反対方向に再生することで、視覚的にも「戻る」感を演出しているわけだ。

Twitterをキーワード検索する ― showPageLoadingMsg/hidePageLoadingMsgメソッド

 ここで作成するのは、Twitterを指定のキーワードで検索し、その結果をページ下部にリスト・ビューとして表示する――典型的なAjaxアプリだ。このようなAjaxアプリでは、ローディング・メッセージ(進捗(しんちょく)アイコン)を表示し、ユーザーに対して、現在処理中であることを明確にすべきだ。これによって、ユーザーによるボタンの二度押しをある程度防ぐことができる。

 それではさっそく、具体的なコードを見てみよう。

<div id="list" data-role="page" data-title="jQuery Mobile">
  <div data-role="header">
    <h1>jQuery Mobile</h1>
  </div>
  <div data-role="content">
    <div data-role="fieldcontain">
      キーワード:
      <input id="keywd" type="search" />
      <input id="search" type="button" value="検索" data-inline="true" />
    </div>
    <!--検索結果を表示するための領域を準備-->
    <div id="listview"></div>
  </div>
  <div data-role="footer">
    Copyright 1998-2012, WINGS Project
  </div>
</div>
$('#search').live('click', function(e, d) {
  // ローディング・メッセージを表示
  $.mobile.showPageLoadingMsg();
  // <div id="#listview">要素の配下をクリ
  $('#listview').empty();
  // Twitterに対するキーワード検索
  $.getJSON(
    'http://search.twitter.com/search.json?callback=?',  // エンドポイント
    { q: $('#keywd').val() },  // 検索キーワード
    // 検索成功時に呼び出されるコールバック関数
    function(data) {
      var tag_str = '<ul id="s_result" data-role="listview" data-inset="true">';
      // 取得結果(JSONデータ)からツイート部分を取得&リスト項目に整形
      $.each(data.results,
        function(index, value) {
          tag_str += '<li><img src="' + value.profile_image_url +
          '" />' + value.text + '</li>';
        }
      );
      tag_str += '</ul>';
      // 組み立てた<ul>/<li>要素を<div>要素配下に埋め込み
      $(tag_str).appendTo('#listview');
      // listviewウィジェットを明示的に呼び出し
      $('#s_result').listview();
      // メッセージを確認するための意図的なスリープ
      for(var i = 0; i < 100000000; i++) {  }
      // ローディング・メッセージを非表示に
      $.mobile.hidePageLoadingMsg();
    }
  );
});
キーワードでTwitter検索するコード(上:loading.html、下:loading.js)

[検索]ボタンをクリックすると、ローディング・アイコンが表示されて……

検索結果がリスト・ビューとして表示される

 Twitterの検索APIや、$.getJSONメソッドについては本稿の主眼から外れるので、関連ページと、サンプル・コード内のコメントを参考にしていただきたい。

 ここでは、クエリ情報「q」でTwitter検索APIに検索キーワード($('#keywd').val())を渡し、その結果をもって、以下のような<ul>/<li>要素を組み立てているとだけ理解しておけばよいだろう。

<ul id="s_result" data-role="listview" data-inset="true">
  <li>
    <img src="http://a0.twimg.com/profile_images/2274002067/profile.jpeg">
    ツイート本文
  </li>
  ……中略……
</ul>
サンプル・コード実行時の<ul>/<li>要素の組み立て例

 jQuery Mobileに関するポイントは、以下の2点のみだ。

(1)ローディング・アイコンの表示/非表示を切り替える

 ローディング・アイコンの表示/非表示を切り替えるのは、showPageLoadingMsg/hidePageLoadingMsgメソッドの役割だ。メソッドそのものは引数を持たず、ローディング・メッセージも表示するかどうか、メッセージの内容などは、全てグローバル設定で指定しなければならない点に注意してほしい。

 なお、(メソッドそのものの用法とはややずれるが)hidePageLoadingMsgメソッドは、$.getJSONメソッドのコールバック関数内に記述しなければならない点にも要注意だ。$.getJSONメソッドは非同期でリクエストを行うためのメソッドだ。そのため、以下のように書いてしまうと、通信の終了を待たずしてローディング・アイコンを非表示にしてしまう。

$.getJSON(
  'http://search.twitter.com/search.json?callback=?',
  function(data) {...}
);
$.mobile.hidePageLoadingMsg();  → $.getJSONの処理が終わる前に実行

(2)リスト・ビューはlistviewメソッドで明示的に呼び出す

 先ほども述べたように、jQuery Mobileではページ・ロードのタイミングでウィジェットなどの初期化処理を実施する。よって、後から要素を動的に追加した場合、そのままの状態ではウィジェットは適用されない点に要注意だ。

 リスト・ビューであれば、タグを組み立て終わったところでlistviewメソッドを呼び出して、明示的にウィジェットを適用しなければならない。

スクロール時にリストの続きを読み込む ― scrollstopイベント

 先ほどのサンプルを修正して、「検索結果を末尾までスクロールすると、リストの続きを読み込む」という仕組みを作成してみよう。このような仕組みも、jQuery Mobileのスクロール・イベントを利用することで、簡単に実装できる。

var next = '';  // 次ページを読み込むためのクエリ文字列

// (1)スクロールを終えたタイミングで実行するコード
$(window).bind('scrollstop', function() {
  var w = $(this);

  // (a)ページ末尾までスクロールした場合に、次データの取得処理を実行
  if (next && w.scrollTop() + w.height() > $(document).height() - 50) {
    $.mobile.showPageLoadingMsg();

    // (2)Twitterから続きのデータを取得
    $.getJSON(
      //(c)次ページ読み込みのための問い合わせURLを組み立て
      'http://search.twitter.com/search.json' + next + '&callback=?',
      null,

      // 検索成功時に呼び出されるコールバック関数
      function(data) {
        next = data.next_page;

        // 取得結果(JSONデータ)からツイート部分を取得&リスト項目に整形
        var tag_str = '';
        $.each(data.results,
          function(index, value) {
            tag_str += '<li><img src="' + value.profile_image_url +
            '" />' + value.text + '</li>';
          }
        );
        // 組み立てた<ul>/<li>要素を<div>要素配下に埋め込み
        $(tag_str).appendTo('#s_result');

        // listviewウィジェットをリフレッシュ
        $('#s_result').listview('refresh');
        $.mobile.hidePageLoadingMsg();
      }
    );
  }
});

// ボタン・クリック時の処理(初回の検索)
$('#search').live('click', function(e, d) {
  $.mobile.showPageLoadingMsg();
  $('#listview').empty();
  $.getJSON(
    'http://search.twitter.com/search.json?callback=?',
    { q: $('#keywd').val() },
    function(data) {
      // (b)次ページを読み込むためのクエリ文字列を保存
      next = data.next_page;
      ……中略……
    }
  );
});
リスト末尾までスクロールしたときに続きのデータを読み込むコード(loading.js)

下までスクロールすると、続きがロードされる
リスト末尾までスクロールすると、リストの続きを動的に読み込む

(1)スクロールはscrollstopイベントで検出できる

 スクロールを終えたことを検出するのは、scrollstopイベントの役割だ。サンプルでは、scrollstopイベントのタイミングで、現在のスクロール位置を検出し、それがページ末尾近くであれば、続きのツイートを読み込むという処理を行っている。

 ページ末尾近くであるかを判定しているのは、以下の部分だ((a))。

w.scrollTop() + w.height() > $(document).height() - 50
ページ末尾近くであるかを判定しているコード

 scrollTopメソッドは垂直方向のスクロール位置、heightメソッドはウィンドウ要素の高さを求めるためのメソッドだ。これらを加算することで、現在表示しているページの下端座標を求められる。一方、「$(document).height()」はページ全体の高さを表す。ここから「50」を差し引いているのは、現在のスクロール位置がページ下端に行き付く少し前で、次のページを読み込むためだ。

(2)Twitterから続きのデータを取得する

 Twitter検索APIで、続きのデータを取得するのはさほど難しい話ではない。というのも、最初の検索で続きのデータを読み込むためのクエリ文字列を返してくれるためだ。

 具体的には、結果オブジェクト「data」のnext_pageプロパティでアクセスできる。サンプルでは、このクエリ文字列を変数「next」にいったん退避させておき((b))、(c)で変数「next」を基に問い合わせURLを組み立てているわけだ。

 以上、本連載では全6回に渡って、jQuery Mobileの基本的な用法について解説してきた。

 前半では、jQuery Mobile標準のウィジェットを利用することで、スクリプトレスでごく手軽に、ネイティブ・アプリ・ライクなサイトを開発できることを実感していただけたことと思う。特に、フォーム関連のウィジェットと、リスト・ビューは利用の頻度も多いウィジェットであるので、確実に理解しておきたいところだ。

 そして、連載後半では、jQuery Mobileの動きをカスタマイズするための、JavaScript APIについて紹介した。独自の注意点もあるものの、jQuery MobileがやはりjQueryのプラグインであることが実感していただけたのではないだろうか。ウィジェットの用法を理解したところで、これらのAPIも習得することで、さらなる応用の手がかりとしてほしい。

 別連載「jQuery逆引きリファレンス」とも併せて、この連載が、読者の皆さんにとってjQuery Mobileを学習する手掛かりとなれば幸いである。end of article

 

 INDEX
  [連載]jQuery Mobile入門(最終回)
  第6回 jQuery Mobile APIでもっとJavaScriptプログラミング
    1.JavaScriptからウィジェットを操作する
  2.jQuery Mobile APIでカンタン・アプリ開発

インデックス・ページヘ  「連載:jQuery Mobile入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH