最新のアプリ

JavaScript を使って構築した Windows ストア アプリのコントロールと設定を習得する

Rachel Appel

優れたユーザー エクスペリエンスとは、フォーム ファクターにかかわらずユーザーに自然かつ直感的にデータを表示することです。最新のエクスペリエンスを構築するための強化された API、コントロール、およびツールを使用して、データとコンテンツを表示する必要があります。Windows ストア アプリでは、必要なコードの量とコントロールの複雑さは、作成するアプリの種類 (生産性アプリ、ゲーム、ソーシャル アプリ、または財務アプリのいずれを作成するか) によって異なります。JavaScript 用 Windows ライブラリ (WinJS) コントロールは、JavaScript を使って Windows ストア アプリを構築している開発者であれば容易に習得できます。このコラムではこれらのコントロールについて説明します。

新しい UI パラダイムと新しい UI コントロールが Windows 8 で導入される

Windows ストア アプリの外観と動作は、以前のバージョンの Windows で動作するプログラムとは大きく異なっています。ユーザーが最初にアプリと対話する部分であるライブ タイルが多数並んでいる新しいスタート ページなど、大幅な機能強化が Windows に施されました。他の顕著な変更としては、Windows ストア アプリが全画面表示モードやスナップ ビューで動作してコンテンツが優先される一方で、コマンドやメニューはユーザーが要求するまで表示されないことが挙げられます。

かつてはあらゆるアプリに存在していた最小化ボタン、最大化ボタン、閉じるボタンなどの Windows UI 要素は、Windows ストア アプリではタッチ スワイプやマウス移動に置き換えられ、もはや存在しません。画面の上部から下部へスワイプするかマウスを下へ移動するだけで、アプリを閉じることができます。メニューさえ、すべての画面の上部にある基本的な固定機能ではなくなりました。Windows ストア アプリでは、タッチ スワイプまたはマウス ジェスチャでアプリ バーの下部から引き出すまで、メニューは表示されません。図 1 に、簡単なカウントダウン タイマー アプリでのメニューの表示例を示します。


図 1 アプリの下部にあるアプリ バー

図 1 からわかるように、メニューはアプリの外側に表示され、コマンド要素は一部にグラフィックスが付属した従来のテキスト本位型メニューではなく、テキストが付属したグラフィック本位型メニューになっています。また、これらの要素は完全に指に合うサイズです。アプリの下部以外にもオプションを配置する領域が必要な場合は、ナビゲーション バーも配置できます。ナビゲーション バーとは単に画面の上部にあるアプリ バーです。

従来の Windows メニューでのナビゲーションは、非常に手間がかかることがあります。だれだって、最初に何を探していたのか忘れてしまうような、深さが 13 階層もあるカスケード メニューを備えたプログラムにうんざりしたことがあるでしょう。Windows ストア アプリでは、ListView 項目でタッチ ジェスチャやマウス ジェスチャを行うと他のページが呼び出されるという意味で、ナビゲーションがコンテンツに組み込まれています。ピンチ ジェスチャを行ったり、Ctrl キーを押しながらマウス ホイールを回したりすると、セマンティック ズームを使ったズーム機能が有効になります ( msdn.microsoft.com/ja-jp/library/windows/apps/hh465438.aspx)。これは Windows ストア アプリにおけるコントロールとナビゲーションの両方に関するパラダイムです。SemanticZoom は、WinJS コントロール一覧 ( msdn.microsoft.com/ja-jp/library/windows/apps/hh465453.aspx) に掲載されています。

HTML と WinJS コントロールを操作する

JavaScript を使った Windows ストア アプリのコントロールには、主に標準の HTML 要素と WinJS コントロールの 2 種類があります。WinJS コントロールは構築済みの JavaScript と結び付けられた HTML で、JavaScript によって HTML 要素の外観や動作が拡張されています。WinJS コントロールも HTML なので、CSS でスタイルを設定できます。図 2 は基本的な WinJS コントロールの例 (WinJS の DatePicker) です。これは年月日を表す複数のドロップダウン コントロールで構成されたコントロールで、以下のコードの既定の出力を示しています。

<span id="eventDate" data-win-control="WinJS.UI.DatePicker" />


図 2 WinJS の DatePicker コントロール

もちろん、図 2 の DatePicker コントロールには既定の WinJS スタイル以外のスタイルが指定されていませんが、.win-datepicker-date、.win-datepicker-month、および .win-datepicker-year の各 WinJS CSS セレクターをオーバーライドして、スタイルを変更することもできます。コントロール全体にスタイルを設定するには .win-datepicker を使用します。

DatePicker (またはあらゆる WinJS コントロール) がこのように機能する理由は、HTML5 の data-* 属性、この場合は data-win-control 属性にあります。data-win-control 属性では、WinJS で所定の位置にレンダリングされるコントロールの種類を指定します。そのため data-win-control 属性の値を WinJS.UI.DatePicker に設定すると、コントロールによって図 2 のドロップダウンがレンダリングされます。data-win-options 属性を使用すると、コントロールに追加のプロパティを設定できます。たとえば、DatePicker では data-win-options 属性を設定して、既定で表示する日付、および日付の最小値と最大値の範囲を指定できます。このコントロールは DatePicker という名前ですが、日付の代わりに時、分、秒などの時刻をキャプチャするようこのコントロールを変更することもできます。

WinJS によってコントロールの最終的な出力結果が構築およびレンダリングされるので、デザイン時の HTML と実行時の HTML はまったく異なります。図 3 に、WinJS によって実行時に host 要素に挿入される HTML を示します。この HTML は DOM Explorer から確認できます ([デバッグ] メニューの [ウィンドウ] をポイントし、[DOM Explorer] をクリックします)。

図 3 年月日のオプションが表示される 3 つのドロップダウンをレンダリングする DatePicker

<span class="win-datepicker" id="eventDate" role="group"
   lang="en-US" dir="ltr" data-win-control="WinJS.UI.DatePicker">
<select tabindex="0" class="win-datepicker-month win-order0"
   aria-label="Select Month">
<option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
<option value="April">April</option>
<!-- more <options> that show the other months -->
</select>
<select tabindex="0" class="win-datepicker-date win-order1"
   aria-label="Select Day">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<!-- more <options> that  show day numbers -->
</select>
<select tabindex="0" class="win-datepicker-year win-order2"
   aria-label="Select Year">
<option value="1913">1913</option>
<option value="1914">1914</option>
<option value="1915">1915</option>
<option value="1916">1916</option>
<!—more <options> that show years -->
<option value="2112">2112</option>
<option value="2113">2113</option>
</select>

DatePicker のような WinJS コントロールの背後で機能しているコードは、WinJS の中核となる他のコードと共に、<ProjectRoot>\References\Windows Library for JavaScript 1.0\js\ui.js ファイルに存在しています。このファイルは、以下のように、Windows ストア アプリ ページの <head> 要素に必要な <script> 参照と同一の <script> 参照で表されることに注意してください。

<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

これらのファイルは WinJS の中核となるコードで構成されているので、開発者自身の責任で編集してください。

DatePicker を含むあらゆる WinJS コントロールには、実行時に winControl という名前のプロパティを通じてアクセスできます。WinJS では、実行時に winControl プロパティに子プロパティが追加されます。これは WinJS コントロール特有の動作です。たとえば、ListView コントロールにはその項目の一覧が含まれています。また、WinJS.UI.Ratings コントロールに対してユーザーが選択した評価をクエリすることもできます。要素の winControl プロパティには、次のようにしてアクセスできます。

var control = document.getElementById("WinJSElementId").winControl

Button、CheckBox、RadioButton、DropDown、TextBoxes などのコントロールはすべて、従来のプレーンな HTML ページでの場合とまったく同じように動作します。しかし、WinJS.UI 名前空間には、複雑なシナリオ向けの、リスト コントロールなどの常に重要な UI コントロールが多数含まれています。

リスト コントロールとグリッド コントロール

さまざまな種類のアプリでデータをグリッドやリストに表示する必要があります。そのため当然ながら、このようなシナリオ向けの ListView と呼ばれるコントロールが存在します。ListView コントロールは、グループ化機能やさまざまなサイズの項目を備えたグリッドまたはリストとしてレンダリングできます。ListView は柔軟性が高いだけでなく、画面に合わせた自動的な拡大縮小、解像度やデバイスのディスプレイ サイズに応じた、可変サイズの行と列へのリスト項目の配置などの処理により、新しい Windows エクスペリエンスで申し分なく機能します。

他のほとんどの WinJS コントロールがスタンドアロンである一方で、ListViews は対応する HTML との連携によるテンプレートとして機能します。このため、図 4 に示すように、テンプレート HTML とコントロール コンテナー自体の両方を設定する必要があります。テンプレートの data-win-control 属性と ListView の data-win-options 属性に、ListView と ListView のテンプレートをリンクする設定が含まれていることに注意してください。

図 4 WinJS の ListView を作成するために必要な HTML

<div id="maincontent">     
  <div id="listViewTemplate"
         data-win-control="WinJS.Binding.Template" >
    <div data-win-bind="style.background: color" class="win-item">
      <h1 data-win-bind=" innerText: daysToGo"></h1>
      <h2 class="subtitle" 
             data-win-bind="innerText: eventTitle"></h2><br />
      <h2 class="subtitle-bottom" 
             data-win-bind=" innerText: eventDate"></h2>
    </div>
  </div>
  <div id="listView" data-win-control="WinJS.UI.ListView"
    class="win-listview"
    data-win-options=
    "{ itemDataSource: Data.items.dataSource,
    itemTemplate: select('#listViewTemplate'),
    selectionMode: 'single'}">
  </div>
</div>

図 4 には 2 つの <div> 要素が含まれています。1 つは listViewTemplate という id のテンプレートで、もう 1 つは listView という名前の ListView 自体です。listViewTemplate 要素には、eventTitle や eventDate など、リストやグリッドの各項目におけるさまざまなフィールドを表す子要素が含まれています。図 4 の ListView を見ると、itemDataSource プロパティが Data.items.dataSource に設定されていることがわかります。ここでの Data は名前空間を指し、items はデータを追加する WinJS.Binding.List を指しています。JavaScript では柔軟に型指定されたデータを操作するので、以下のコードのように、List コンストラクターにオブジェクトの配列を格納するだけで、ListView コントロールにバインドする準備が整います。

WinJS.Namespace.define("Data", {
    items: []
});

// NOTE: The 'month' parameter for the Date constructor expects
// the month as a 0-based index (Jan = 0; Dec = 11).
var list = [
  { eventTitle: "Rachel's Birthday", 
   eventDate: new Date(2014, 0, 13) },
  { eventTitle: "Rachel's BFF's Birthday", 
    eventDate: new Date(2013, 4, 29) }
];

list.map(function (item) {
    var daysToGo = item.eventDate.getTime() - Date.now();
    item["daysToGo"] = (daysToGo / (1000 * 60 * 60 * 24)).toFixed();
});

Data.items = new WinJS.Binding.List(list);

別の方法として、配列を List のコンストラクターに渡す代わりに、push メソッドを使用して項目を List オブジェクトにプッシュすることもできます。ListView でデータを管理する最適な方法は、AppBar コントロールで関連オプション (add、delete など) を公開することです。

アプリ バーとコマンド

クロムよりもコンテンツを重視することは、マイクロソフトの重要なデザイン原則です。アプリ バーは、通常は表示されないまま、ユーザーが必要とするときにオプションを表示するために待機しているので、このデザイン原則に不可欠な要素です。コードでは、アプリ バーは単なる <div> 要素であり、アプリ バー コマンドと呼ばれる、data-win-control 属性が WinJS.UI.AppBarCommand に設定された <button> 要素が 1 つ以上含まれています。個々のアプリ バー コマンドを区別する特徴は、ご想像のとおり data-win-options 属性に含まれています。

図 5 の各アプリ バー コマンドの data-win-options 属性を調べると、各コマンドの ID、ラベル、アイコン、およびセクションがわかります。アプリ バー ボタンをアプリ バーのグローバル セクションに割り当てることも (ボタンがアプリの画面右下に表示されます)、section オプションを selection に設定することもできます (ボタンが左下に表示されます)。また、アプリ バー コマンドの section オプションを selection に設定することは、ユーザーが ListView の項目をスワイプやクリックで選択したときに使用する、状況に応じて表示するコマンドにすることを意味します。

図 5 アプリ バーの作成

<!-- HTML -->
<div id="appbar" class="win-appbar" 
       data-win-control="WinJS.UI.AppBar">
<button data-win-control="WinJS.UI.AppBarCommand"
   data-win-options="{id:'deleteButton', 
    label:'Delete',
    icon:'delete', section:'selection'}" 
    type="button"></button>
<button data-win-control="WinJS.UI.AppBarCommand"
   data-win-options="{id:'addButton', 
    label:'Add', icon:'add',
    section:'global'}" 
    type="button"></button>
<button 
   data-win-control="WinJS.UI.AppBarCommand"
   data-win-options="{id:'refreshButton',
   label:'Refresh',
   icon:'refresh', 
   section:'global'}" 
   type="button"></button>
</div>
// JavaScript
document.getElementById("addButton").addEventListener(
  "click", this.addButtonClick);
document.getElementById("deleteButton").addEventListener(
  "click", this.deleteButtonClick);
document.getElementById("refreshButton").addEventListener(
  "click", this.refreshButtonClick);

HTML ページに関連する JavaScript ファイルでは、他の HTML 要素の場合と同様にイベント リスナーをアプリ バー ボタンにアタッチします。アプリ バーは (プログラムで呼び出すこともできますが) ユーザーのコマンドに応じて自動的に表示と非表示が切り替わるので、アプリ バー自体を表示するためのリスナーは必要ありません。図 5 の例は、データを追加、削除、および更新するためのボタンを完備したアプリ バーを示しています。

シナリオ上必要であれば、アプリ バー ボタンの表示、非表示、有効化、および無効化を行うためのコードを記述することもできます。

ポップアップ

タッチスクリーンは標準的になっているので、お気付きかもしれませんが、UI 要素やダイアログ ボックスが表示されているときに画面の他の場所をタップまたはクリックするだけで、UI 要素やダイアログ ボックスを閉じることができます。この暗黙的にダイアログ ボックスを閉じるという考え方は "簡易非表示" と呼ばれ、Windows 8 の MessageDialogs と PopupMenus の既定の動作になっています。これは、簡易表示が閉じるボタンを扱うよりもユーザーにとってはるかに容易なためです。

前述のコントロールと同様、ポップアップには data-win-control 属性を使用して、その要素が WinJS.UI.Flyout コントロールであることを指定します。ポップアップの <div> 要素の子要素はポップアップ内にレンダリングされます。たとえば、図 6 のコードに示すように、ポップアップに HTML フォームを配置してユーザーが今後のイベントのタイトルと日付を入力できるようにし、図 7 のようなポップアップを作成する場合が考えられます。

図 6 WinJS コントロールで情報を収集する簡易非表示ポップアップ

<!-- HTML  -->
<div id="eventFlyoutPanel" data-win-control="WinJS.UI.Flyout">
  <table width="100%" height="100%">    
    <tr><td>Event Title:</td><td><input type="text"
 id="eventTitle"/></td></tr>
    <tr><td>Event Date:</td><td id="eventDate"
       data-win-control="WinJS.UI.DatePicker"></td></tr>        
    <tr><td>&nbsp;</td><td align="right">
    <input type="button" id="confirmButton" value="Submit" /></td></tr>
    </table>
</div>
// JavaScript
addButtonClick: function () {
  document.getElementById("eventFlyoutPanel").winControl.show(
  "addButton", "top");
}


図 7 情報を収集するポップアップ

図 7 のポップアップが単なる HTML フォームであることに注目してください。ユーザーが [Add] アプリ バー コマンドをタップまたはクリックすると、図 6 の addButtonClick 関数で指定されているようにポップアップが表示されます。ポップアップは他のコントロールに対して相対的な位置に表示されます。そのため winControl.show メソッドを呼び出すときは、コントロールのアンカー要素の名前と、そのコントロールの配置場所 (アンカー コントロールの上端または下端に隣接する位置) を渡します。

ポップアップは簡易非表示コントロールなので、ユーザーはポップアップ以外の任意の場所をタップまたはクリックすれば閉じることができます。明らかにモーダル ダイアログ ボックスが Windows ストア アプリには欠如していることにお気付きかもしれませんが、これはマイクロソフトのデザイン理念の一部です。デザイン分野の関係者は、ユーザーをいら立たせたり、ユーザーの自由な行動を阻んだりするあらゆる要素をデザイン上不適切だと見なすというもっともな理由から、モーダル ダイアログ ボックスを良しとしていません。

ポップアップには、SettingsFlyout という種類もあります。SettingsFlyout によって、以前のバージョンの Windows でアプリのユーザー設定を管理していた方法が大きく変わりました。

アプリの設定

Windows ユーザーであれば、複雑怪奇な設定を含むダイアログ ボックスを起動する、お決まりの [ツール] メニューの [オプション] コマンドまたは [ヘルプ] メニューの [バージョン情報] コマンドを 1 回は経験したことがあるでしょう。さいわい、Windows ストア アプリでは、これらのダイアログ ボックスの代わりにユーザーにとってより直感的な機能が使用されるようになりました。これらの [設定] ページと [バージョン情報] ページはどちらも、ユーザーが Windows チャーム の [設定] アイコンをクリックすると呼び出される、長い縦長のポップアップ コントロールとして動作します ( windows.microsoft.com/ja-jp/windows-8/charms)。

設定の動作は、どの Windows ストア アプリでも一貫しています。ユーザーが設定チャームを呼び出すと、実行中のアプリに関係なく、同一の SettingsFlyout が右側に表示されます。SettingsFlyout には、プライバシー ポリシー、ユーザー設定、ヘルプなどへのリンクが配置されます。プライバシー ページやオプション ページへのリンクを作成するには、通常は /js/default.js に含まれている app.onactivated イベントに、コードを数行記述するだけです。

// In default.js, app.onactivated

WinJS.Application.onsettings = function (e) {

  e.detail.applicationcommands =
   { "privacypolicy": { title: "Privacy Policy",
 href: "privacy.html" } };

    WinJS.UI.SettingsFlyout.populateSettings(e);

};

ユーザーが設定チャームのいずれかのリンクをタップまたはクリックすると、対応するポップアップが表示されます。図 8 に、プライバシー ポリシー情報が含まれた SettingsFlyout の HTML を示します (明確で簡潔なプライバシー ポリシーは、Windows ストアでアプリを公開するための要件です)。

図 8 プライバシー ポリシー情報が含まれた SettingsFlyout の HTML

<div id="settingsFlyout" 
  data-win-control="WinJS.UI.SettingsFlyout"
  data-win-options="{settingsCommandId:'privacypolicy', width:'narrow'}">
  <div class="win-header" style="background-color:#312e2e">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()"
       class="win-backbutton"></button>
    <div class="win-label">Privacy Policy</div>
  </div>
  <div class="win-content">
    <div class="win-settings-section">
      <p>This application does not collect any personal information.</p>
      <p>Internet access is only used to retrieve data from the web,<div id="settingsFlyout" 
  data-win-control="WinJS.UI.SettingsFlyout"
  data-win-options="{settingsCommandId:'privacypolicy', width:'narrow'}">
  <div class="win-header" style="background-color:#312e2e">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()"
       class="win-backbutton"></button>
    <div class="win-label">Privacy Policy</div>
  </div>
  <div class="win-content">
    <div class="win-settings-section">
      <p>This application does not collect any personal information.</p>
      <p>Internet access is only used to retrieve data from the web,
         or to allow you to contact the developer:</p>
          <p>
            <a href="mailto:rachel@rachelappel.com">Email Rachel Appel </a>
 <br />
            <a href="http://rachelappel.com/privacy-policy"
             target="_blank">View privacy statement online</a>
          </p>
      </div>
  </div>
</div>

         or to allow you to contact the developer:</p>
          <p>
            <a href="mailto:rachel@rachelappel.com">Email Rachel Appel </a>
 <br />
            <a href="http://rachelappel.com/privacy-policy"
             target="_blank">View privacy statement online</a>
          </p>
      </div>
  </div>
</div>

必ず、プライバシー ポリシーの設定ファイルには、ポップアップの登録で使用した href 引数と同じ名前を付けてください (図 8 参照)。

設定チャームに配置できるコンテンツはプライバシー ポリシーだけではありません。SettingsFlyout にはあらゆる有効な HTML を含めることができ、多くの場合は、[ツール] メニューの [オプション] ダイアログ ボックスでホストしている ToggleSwitch、CheckBox、DropDown、および機能を SettingsFlyout でホストします。ただし、前述のように SettingsFlyout は簡易非表示コントロールなので、モーダル ダイアログ ボックスとは異なり、他の場所をタップするだけでポップアップが閉じます。Windows ストア アプリ開発のシンプルながらも新しいパラダイムには、SemanticZoom コントロールという使い勝手の良いナビゲーション ヘルパーもあります。

セマンティック ズーム

アプリによっては、大量のデータを扱います。このようなアプリのナビゲーションは、大量のデータを扱っている場合は特に、一筋縄では行かないことがあります。セマンティック ズームが役立つのはこのような状況です。セマンティック ズームを使用すると、拡大と縮小という 2 つのデータ ビジュアル化モードを表現できます。既定である拡大モードを使用すると、可能な限りすべてのデータが表示されるので、ユーザーは画面をパンまたはスクロールする必要があります。縮小モードでは、通常はデータが情報集約された形式にまとめられるので、ユーザーが容易に任意のデータ領域に移動してから特定のデータ項目を拡大できます。

図 9 に示すように、SemanticZoom コントロールは、1 つのホスト コントロールと 2 つのズーム コントロールという、3 つのコントロールのセットです。子コントロールをセマンティック ズームの対象にするには、IZoomable を実装する必要があります。そのため、WinJS アプリの場合、セマンティック ズームが機能するのは ListView だけです。

図 9 SemanticZoom コントロールのコード

<div id="semanticZoomDiv" data-win-control="WinJS.UI.SemanticZoom">            
  <!-- The zoomed-in view. -->   
  <div id="zoomedInListView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{ itemDataSource:
      myData.groupedItemsList.dataSource,
     itemTemplate: select('#mediumListIconTextTemplate'),
     groupHeaderTemplate: select('#headerTemplate'),
     groupDataSource: myData.groupedItemsList.groups.dataSource,
     selectionMode: 'none',
     tapBehavior: 'none',
     swipeBehavior: 'none' }">  </div>
  <!-- The zoomed-out view. -->
  <div id="zoomedOutListView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{ itemDataSource:
     myData.groupedItemsList.groups.dataSource, itemTemplate:
     select('#semanticZoomTemplate'), selectionMode: 'none',
     tapBehavior: 'invoke', swipeBehavior: 'none' }">
  </div>
</div>

ご覧のように、セマンティック ズームでは 2 つの ListView を切り替えているだけですが、ユーザーにとっては優れた代替移動手段であり、開発者にとっては実装が容易になります。

その他のコントロール

進行状況バー、フリップ ビュー、ポップアップ メニュー、メッセージ ダイアログ、評価など、他のコントロールも存在します。どれも新しい Windows エクスペリエンスに不可欠な要素ですが、ここにはすべてを説明するスペースがありません。HTML5 や ECMAScript 5 (ES5) などのオープン標準が WinJS の全機能の基盤になっているので、Web の必須機能からアンカー、HTML5 のオーディオとビデオへの入力までのすべての機能が、Windows ストア アプリ開発プラットフォームの一部として適切に機能します。


Rachel Appel は 20 年を超える IT 業界での経験を持つマイクロソフトの元社員で、コンサルティング、執筆活動、および指導を行っています。彼女は Visual Studio Live!、DevConnections、MIX など、業界トップ クラスのカンファレンスで講演しています。専門分野は、マイクロソフトの各種開発ツールやオープン Web を重視したテクノロジとビジネスを連携させるソリューションの開発です。Appel についてもっとよく知るには、彼女の Web サイト rachelappel.com (英語) を参照してください。

この記事のレビューに協力してくれた技術スタッフの Keith Boyd (マイクロソフト) に心より感謝いたします。