Web 開発の経験がある方ならば、Sencha の名前は耳にしたことがあるでしょう。あるいは、Ext JS と呼ばれていた頃、さらには YUI-Ext (Yahoo! UI フレームワークの拡張機能) と呼ばれていた時代に使用したことがある方もいるかもしれません。ここ数年の間に、このフレームワークは YUI-Ext、Ext JS、Ext 2.0、Ext 3.0 とさまざまに名前を変え、現在の Sencha Touch という名前に至っています。モバイル Web アプリケーションに新たに重点を置くようになった理由は、一部に jQTouch が Ext JS に「マージ」されたことによりますが、この記事を読むとわかるように、Sencha Touch は jQTouch とはまったく異なります。
まず、Sencha Touch は jQuery にはまったく依存せずに、Ext JS をベースに作成されています。言うまでもなく、Ext JS はこれまでずっと、jQuery や Prototype などの他の JavaScript ライブラリーとの親和性に定評がありました。また、Ext JS のセールスポイントには、よりオブジェクト指向な API 一式を完備したウィジェット・ライブラリーも含まれます。これらの機能は Sencha Touch にも備わっていますが、Sencha Touch のウィジェット・ライブラリーは一新されていて、特に iOS および Android 機器のモバイル・ブラウザーを対象に最適化されています。Sencha Touch をモバイル Web アプリケーションに利用する方法について理解を深めるには、サンプル・アプリケーションを見てください。このサンプル・アプリケーションは、連載のこれまでの記事のそれぞれで構築したイントラネット用の従業員ディレクトリー・アプリケーションを新しくしたバージョンです。サンプル・アプリケーションのソース・コードについては、「ダウンロード」を参照してください。
Sencha Touch アプリケーションの開発
この連載では、これまでクライアント・サイドの Web アプリケーション・フレームワークをいくつか取り上げてきました。これまで取り上げたフレームワークと Sencha Touch とを区別するものは何かと言うと、その答えは、Sencha Touch は Ajax 呼び出しを行うためのユーティリティーから、豊富な UI ウィジェットまでのすべてを揃えた完全なフレームワークであるとともに、モバイル Web ブラウザー用に作成されているという点です (具体的には、Sencha Touch は iOS および Android 機器の WebKit ベースのブラウザー用に作成されています。けれども、モバイル分野では WebKit ベースのブラウザーが優勢を保っていることから、Sencha Touch が対象とするモバイル機器のリストは将来的に拡大される可能性があります)。この Sencha Touch とモバイル Web ブラウザーとの組み合わせは独特であり、極めて魅力的でもあります。
さらに、Sencha Touch は、まだその真価が問われていない新しいモバイル Web フレームワークというわけではありません。Sencha Touch に進化するまでのフレームワークは、長年にわたって Web 開発者たちの間で人気を誇ってきました。Sencha Touch はアクティブな開発者たちによって支えられ、このフレームワークを中心とした大きなコミュニティーも広がっています。しかも、Adobe の ColdFusion のような大規模な開発フレームワークが Sencha Touch を再パッケージ化して再利用しています。
ご推察の通り、Sencha Touch が Web 開発者の間で大きな人気を博している理由は、Ext JS の多くの機能を引き継いでいるためです。Sencha Touch はアプリケーションを開発するための完全なフレームワークとなるだけでなく、オブジェクト指向のフレームワークにもなります。遥か以前の Smalltalk-80 の時代まで遡ると、当時のユーザー・インターフェース・フレームワークではオブジェクト指向モデルが使用されていました。オブジェクト指向プログラミングはすべてのプロブラミング問題にとって最善の解決策となるわけではありませんが、大多数のユーザー・インターフェースの問題には適しています。JavaScript はオブジェクト指向であると見なせるものの、通常のオブジェクト指向のようにクラスをベースにしてはいません。JavaScript が使用しているのは、プロトタイプ・ベースのオブジェクト指向プログラミングです。したがって、開発者はクラスを継承する代わりに、クラスのインスタンスを複製してそのプロトタイプを変更し、既存のオブジェクトをオーバーライドするか、新しい振る舞いを追加するという方法を採ります。大抵の開発者は、このようなスタイルのオブジェクト指向プログラミングには慣れていません。慣れているのは、クラス・ベースの継承です。そこで、Ext JS は、開発者がクラス・ベースのオブジェクト指向プログラミングを行えるようにする、JavaScript をベースとしたユーティリティーを提供しています。しかもさらに踏み込んで、従来の (クラス・ベースの) オブジェクト指向コンポーネント・モデルを使用する広範な UI ウィジェット・ライブラリーまで作成しています。それと同時に、Ext JS はイディオムのような JavaScript を使用します。例えば、ほとんどのExt JS オブジェクトのコンストラクターは、唯一の入力引数としてJavaScript オブジェクト・リテラルを取ります。このオブジェクトは構成オブジェクトであると見なせますが、多くの点で、名前付きパラメーターを引数に持つコンストラクターを使用しているのと同様です。これは、オブジェクトを正しく構成するためにコンストラクターに渡す必要のある値のリストがかなりの長さになる可能性がある場合には極めて好都合です。
もちろん、Sencha Touch は単なる Ext JS ではなく、モバイル Web 用に最適化されています。これは、そのウィジェットが小さな画面を念頭に設計されているというだけでなく、タップやスワイプなどのタッチ・イベント、そして機器の向きの変化に対処するように設計されていることも意味します。全体的に見て、これは非常に強力な機能セットです。ただし、ほとんどの開発者にとって百聞は一見に如かずなので、実際に Sencha Touch で駆動するサンプルのモバイル Web アプリケーションを紹介します。
データ・モデル、ストア、Ajax
この記事で用いるサンプル・アプリケーションは、連載で使用してきた従業員ディレクトリー・アプリケーションとはまた別の実装です。このアプリケーションは従業員とそれぞれの連絡先情報のリストを表示することを思い出してください。Sencha Touch では、アプリケーションのデータ・モデルを定義することができます。Employee のデータ・モデルは、リスト 1 のようになります。
リスト 1. Sencha Touch スタイルの Employee データ・モデル
Ext.regModel('Employee', {
fields: [
{name:'firstName', type: 'string'},
{name: 'lastName', type: 'string'},
{name:'email', type:'string'},
{name: 'phone', type: 'string'}
]
});
Sencha Touch では簡単にモデルとそのフィールドを定義できるようになっており、それぞれ名前と型を定義するフィールドの配列を指定すればよいのです。その結果、この後説明するように、このモデルを UI コンポーネントと併せて使用できるようになりますが、とりあえず今のところは、構文解析して Employee オブジェクトにすることができるリモート・データをロードします。このタスクには、Sencha Touch のデータ・ストア・オブジェクト (そして、ちょっとした Ajax) を使用します。データ・ストアを定義する方法は、リスト 2 のとおりです。
リスト 2. Sencha Touch データ・ストアの作成
var store = new Ext.data.JsonStore({
model : 'Employee',
sorters: [
{property: 'lastName', direction: 'ASC'},
{property: 'firstName', direction: 'ASC'}
],
getGroupString : function(record) {
return record.get('lastName')[0];
},
proxy : {
type : 'ajax',
url : 'app/employees.json',
reader : {
type : 'json',
root : 'employees',
idProperty : 'email'
}
},
autoLoad : true
});
データ・ストアは、Sencha Touchフレームワークに欠かせない重要な部分です。データ・ストアが提供するモデル・オブジェクトのクライアント・サイドのキャッシュは、このフレームワークのさまざまな UI コンポーネントで利用することができます。その役割は、リモート・データの取得、データのクエリー、データのソートなど、さまざまです。リスト 2 のストアは、そのモデルとしてリスト 1 で登録された Employee を宣言し、続いてそのデータ (lastName および firstName) に対するソーターを宣言しています。これにより、データの自然なソートが行われ、lastName を基準に昇順でソートされてから、同じく昇順で firstName を基準にソートされることになります。次にストアが宣言しているのは getGroupString 関数です。この関数をストア内の各レコード (Employee) に適用することで、それらのレコードをグループ化することができます。上記の例ではこの関数に対し、lastName を引数に取り、その最初の文字を使用するように指示しています。こうすることによって、例えばラストネームが「G」で始まるすべての従業員が 1 つのグループにされることになります。この関数が使用されるのは、グループ化をサポートする UI コンポーネントのなかでのみです。これから使用するコンポーネントはグループ化をサポートするので、この関数をストアに追加して、グループ化を利用できるようにしてください。
次のセクションでは、ストアのプロキシーを記述します。Sencha Touch には、数種類のプロキシーがあります。その 1 つは、HTML5 の localStorage オブジェクトを使用する Ext.data.LocalStorageProxy というプロキシーです。localStorage を使ってデータをローカルに保存してある場合、そのデータを LocalStorageProxy を使ってロードして、Sencha Touch の UI コンポーネントで使用することができます。これは、Sencha Touch が iOS と Android のブラウザーで使用可能な HTML5 機能を提供する方法を説明する好例です。
リスト 2 の例に使用するデータは、まだローカルに保管されていません。データはリモート・サーバー上にあり、Ajax を使用してロードする必要があります。そこで、このストアには Ext.data.AjaxProxy のインスタンスとなるプロキシー・オブジェクトを宣言します。このようなオブジェクトを明示的に作成して、それをストア・オブジェクトの config オブジェクト (コンストラクター) 内に指定することもできますが、ここではプロキシーにconfig オブジェクトを指定し、よりイディオムに近い JavaScript を使用する方法を選びました。AjaxProxy インスタンスを取得するには、プロキシーの type プロパティーを指定し、続いてデータを取得するための URL を指定すればよいのです。
次に指定するのは、Ext.data.Reader のインスタンスを指定する reader プロパティーです。このオブジェクトを使用して、サーバーから受信した状態のデータを処理し、プロキシーがストアに提供するモデル・オブジェクトのインスタンスに変換します。ここでもまた、ストアとそのプロキシーの前に明示的に Reader のインスタンスを作成することもできましたが、代わりに config オブジェクトとして渡される JavaScript オブジェクト・リテラルを使ってリーダーを構成するという方法を採りました。リーダーを作成するには、想定するデータの種類 (JSON)、データ構造のルート要素、そして ID として使用するモデルのプロパティーを指定します。そして最後に、データの autoLoad を実行するようにストアを構成します。つまり、ストアができるだけ早くデータを取得できるようにします。これで、ストアの作成が完了し、ストアをサポートするリモート・データがロードされました。次はこのデータを使って、モバイル用に最適化されたユーザー・インターフェースを作成します。
モバイル用に最適化されたウィジェット
Ext JS はこれまで常に、直観的なオブジェクト指向の API 一式によって支えられた豊富な UI ウィジェットを提供するフレームワークとして知られてきました。Sencha Touch もこの伝統を引き継いでいますが、このフレームワークに含まれているのは、モバイル機器を対象に設計されたウィジェットです。このサンプル・アプリケーションでは、モバイル機器で最適に表示されて円滑に機能する、何らかの形の従業員リストを作成する必要があります。このような一般的な使用例に対応するために Sencha Touch が提供しているのが、Ext.List コンポーネントです。リスト 3 に、List コンポーネントを使用して、このアプリケーションで従業員オブジェクトを表示する方法を示します。
リスト 3. List コンポーネントの使用
var list = new Ext.List({
store : store,
tpl : new Ext.XTemplate(
'<tpl for=".">',
'<div class="contact">',
'{firstName} <strong>{lastName}</strong>',
'</div>',
'</tpl>'
),
itemSelector : 'div.contact',
singleSelect : true,
grouped : true,
indexBar : true,
floating : true,
width : 350,
height : 370,
centered : true,
modal : true,
hideOnMaskTap: false,
fullscreen : true
});
List コンポーネントに最初に指定するのは、このコンポーネントの store プロパティーです。データ・ソースとなるのはリスト 2 で作成した store インスタンスなので、単純にこのインスタンスをプロパティーに指定します。次に指定するのは tpl プロパティー、つまりテンプレートです。tpl は、ストア内の従業員オブジェクトのそれぞれに適用されます。Sencha Touch では単純なテンプレート言語を使って、動的データ要素を組み込んだ HTML を作成することができます。これは、JSP (Java Server Pages)、PHP、または ERb (Embedded Ruby) テンプレートと同様の仕組みです。例として、firstName = 'John' および lastName = 'Smith' となっている従業員がいる場合、上記の tpl プロパティーはリスト 4 の内容を生成します。
リスト 4. Sencha Touch テンプレートで生成された HTML の例
<div class="contact">
John <strong>Smith</strong>
</div>
リスト 3 に話を戻すと、次に指定するのは itemSelector プロパティーです。これは、コンポーネントがイベントを発生させたときに、Sencha Touch が処理対象のノードを判断するために使用する CSS セレクターです。この後すぐにわかるように、Sencha Touch にはカスタマイズできる有用な多くの振る舞いが組み込まれていますが、これらの振る舞いを利用するには、itemSelector プロパティーを指定する必要があります。この例では、リストに含まれる従業員オブジェクトのそれぞれが、contact クラスを指定した div の中にラップされるという点を利用します。
リスト 3 では、List コンポーネントを作成するために、他にもいくつかのプロパティーが config オブジェクトに設定されています。これらのプロパティーのほとんどは、単純な UI 関連のプロパティーですが、興味深いプロパティーとしては singleSelect と grouped の 2 つがあります。前者はリスト内の複数の項目を一度に選択できるかどうかを指定するプロパティーです。後者はリスト内の項目をグループ化するかどうかを指定するプロパティーで、この例では true に設定されています。このグループ化を処理する関数 (getGroupString) を指定する方法は、リスト 2 に記載したとおりです。最後にもう 1 つ注意しておく点として、indexBar プロパティーはリスト内を移動するための索引を生成します。
Sencha Touch は iOS 機器の場合でも、Android 機器の場合でも、同じように魅力的な UI を作成します。リスト 1 で登録したモデルをもう一度見てみると、アプリケーションが保管しているデータは、リスト・ビューに示されているデータよりも多いことがわかります。そこで、ここからは、ユーザーがリスト・ビューから開くことのできる従業員の詳細ビューを作成する方法を説明します。
イベント処理とテンプレート
Sencha Touch は、タップ、スワイプ、ピンチ・ズーム、さらにはローテーションなどのモバイル機器やタッチ機器に固有の便利なイベントを数多く提供しています。このサンプル・アプリケーションで最終目標とするのは、ユーザーがリスト・ビュー内の従業員をタップすると、その従業員に関する詳細情報が表示されるようにすることです。リスト 5 に、この目標を達成する方法を示します。
リスト 5. 詳細パネルのオープン
list.on('itemtap', function(dataView, index, item, e){
var employee = dataView.store.data.items[index].data;
var template = new Ext.XTemplate(
'<p>Name: {firstName} {lastName}</p>',
'<p>Email: {email}</p>',
'<p>Phone: {phone}</p>'
);
var str = template.apply(employee);
var panel = new Ext.Panel({
floating : true,
width : 250,
height : 155,
centered : true,
modal : false,
hideOnMaskTap: false,
dockedItems: [{
dock: 'top',
xtype: 'toolbar',
title: employee.firstName + ' ' + employee.lastName
},{html:str}]
});
var btn = new Ext.Button({
text: 'Close',
ui: 'action',
handler: function(){
panel.hide();
}
});
panel.addDocked(btn);
panel.show();
});
タップ・イベントを処理するには、list の on 関数を使用して itemtap イベントをリッスンすればよいのです。Sencha Touch に含まれるすべての UI コンポーネントにはこれと同様の on 関数がありますが、リッスンする対象にできるイベントは、コンポーネントによって異なります。ここでは単純に itemtap をリッスンして、このイベントが発生したときに実行する関数 (closure) を渡してください。この関数には Ext.DataView オブジェクト (Ext.List の親クラス)、タップされた項目の索引、タップされた UI ノード、そしてイベント・オブジェクトが渡されます。リスト 5 では、dataView (つまり、List コンポーネント) が、タップされた従業員の名前に対応する Employee オブジェクトを取得します。ここでも Sencha Touch のテンプレート・システムを利用して、タップされた従業員の連絡先情報を表示する HTML を作成します (この例では、template の apply メソッドを使って直接 HTML を作成することに注意してください)。次に、 Ext.Panel オブジェクトを作成します。これも、Sencha Touch でよく使用されている UI ウィジェットの 1 つです。パネル内のタイトル・バーと閉じるボタンの両方を作成し、この 2 つのオブジェクトを HTML テンプレートと一緒にパネルに配置します。閉じるボタンには、単にパネルを閉じるだけのハンドラー関数を指定してください。これで、後は単純にパネルを表示すればよいのです。
このように、100 行足らずの JavaScript で、Ajax を使用してリモート・データをロードするインタラクティブなモバイル Web アプリケーションを作成しました。このアプリケーションは、iOS 機器でも、Android 機器でも同じように上手く機能します。これで、Sencha Touch に大きな関心が集まっている理由がわかったはずです。Sencha Touch は、不要なボイラープレート・コードを省いた有用な機能をふんだんに提供してくれます。
まとめ
この記事では、Sencha Touch が完全なモバイル Web アプリケーション・フレームワークとなっている経緯と理由を見てきました。Sencha Touch はデータの取得からモバイル対応の UI の作成、そしてタッチ・イベントの処理に至るまで、あらゆる作業を引き受けてくれます。Sencha Touch は、アプリケーション開発者にとって親しみやすいオブジェクト指向プログラミングのパラダイムを提供すると同時に、オブジェクト・リテラルやクロージャーなどの JavaScript が持つ強力な機能の多くを利用します。新しく進化している分野、つまりモバイル Web の分野でのこのフレームワークの完成度と機能は注目に値します。Sencha Touch は多くの点において瞬く間に、他のフレームワークを評価する際の究極の基準となりました。
0 件のコメント:
コメントを投稿