|
事業仕分けによる次世代スーパーコンピューターの開発予算削減について、どうお考えですか?
|
AJAXアプリケーションで標準的なブラウザナビゲーションを再現するはじめにAJAXは、デスクトップアプリケーションと同じくらい対話性と応答性のよいリッチなWebアプリケーションを開発する手段として、多くの開発者に採用されてきました。AJAXでは、WebのUIを異なるセグメントに分割します。ユーザーはあるセグメントで操作を実行し、その操作が終わらないうちに他のセグメントで作業を開始することができます。 しかし、AJAXには大きな欠点があります。戻る、進む、ブックマークといった標準的なブラウザ機能が無効になるのです。AJAXアプリケーションの開発者は、ユーザーをAJAXの欠点に無理やり順応させるのではなく、アプリケーションを従来のWebインタラクションスタイルに合わせ、次の機能を提供するようにしなければなりません。
典型的なAJAXアプリケーションは最初の3つの機能を実現していません。XMLHttpRequestオブジェクトやDOM更新などのAJAXテクノロジを使用する動的なWebアプリケーションは、ブラウザの履歴を正しく更新しません。なぜなら、バックグラウンドリクエストを使ってデータを取得すると、ページURLが変更されないからです。そのため、ユーザーが[戻る]ボタンをクリックすると、おそらくWebアプリケーションから彼方にジャンプして、保存された状態が失われることになるでしょう。[更新]ボタンをクリックすると、AJAXアプリケーションが再初期化され、現在のページの初期状態に戻ります(実際、アプリケーションが再起動されることが多いでしょう)。同じ理由で、ブックマークも機能しません。ブックマークを使ってAJAXのURLに戻っても、ユーザーがブックマークを付けた時点のページ状態にならないかもしれません。 ユーザーの立場からすると、標準的なナビゲーション動作はとても重要です。ユーザーはWebアプリケーションで一定のインタラクションが当然起こるものと期待しますが、典型的なAJAXアプリケーションでは必ずしもそうならないのです。たとえば、ユーザーがブラウザのURLを使ってページにブックマークを付けた場合、そのページを作成するためにAJAXアプリケーションが作成した中間ステップ(バックグラウンドリクエスト)についての情報は失われます。また、ユーザーがブラウザの[戻る]ボタンをクリックすると、前のページが表示されますが、これは一般に前のページ状態ではありません。AJAXアプリケーションでは「ページ」と「ページ状態」の違いが重要になります。なぜなら、この2つはユーザーにとっては同じことでも、ブラウザにとってはまったく別物だからです。 例として、AJAXベースの検索アプリケーションを考えてみましょう。最初のページには、ユーザーが検索条件を入力する検索フォームが含まれています。これをPage1とします。ユーザーが入力したフォームを送信すると、最初の数個の検索結果が含まれたページ(Page2)が表示されます。このページには、次の検索結果セットを含むページ(Page3)を見るためのリンクが表示されます(さらに後続のページがある場合は、同様に続きます)。アプリケーションがPage3のための次の検索結果セットを取得するためには、非同期呼び出しを送信し、取得したデータをPage2のDOM構造に入れるという処理を行います。このとき、ページ状態は変化しますが、ページのURLは変化せずPage2のままです。つまり、ユーザーは新しいページ(Page3)を見ているつもりでも、ブラウザ上ではこのアプリケーションの履歴スタックは次のようになっているのです。 Page2 Page1 そのため、ユーザーはPage3で[戻る]ボタンをクリックしたときに、当然、最初の検索結果セット(元のPage2)が表示されるものと期待しますが、ブラウザは実直にPage1に戻ります。同様に、ユーザーがPage3を見ているときにページの更新を行うと、代わりにPage2が表示されます。このような直観に反した動作により、ユーザーが混乱し、アプリケーションが使いにくくなります。 解決策AJAXアプリケーションで作成される各ドキュメントをそれ自身のURLでアドレスできれば、[戻る]ボタンとブックマークの問題を解決できるでしょう。この検索アプリケーションが最初の結果ページと2番目のページを別々のURLで参照していることに注目してください。つまり、2つのURLがそれぞれ異なるリソースドキュメントを指しているわけです。しかし、実際にAJAXドキュメントを構成している要素は、開始時点のドキュメントと、ドキュメントのノードを追加、削除、変更する不定の数のDOM操作です。したがって、ある時点のAJAXドキュメントを再作成するには、まず開始時点のドキュメントのURLを取得したうえで、目的の時点までに行われたDOM変更を適用する必要があります。各AJAXリクエストが一意のURLを持っていれば、ずっと簡単にできるでしょう。 URLハッシュの入力URLハッシュとは、シャープ記号(#)の後に続くURL部分です。通常、URLハッシュは他のページではなく、同じページ内の特定の位置を指すので、長いページ内の特定の位置にジャンプするためのリンクで使われます。しかし、必ずしもそういう使い方をする必要はありません。URLハッシュを使って、DOM操作に関する情報をAJAXアプリケーション内に格納する、つまり各AJAXリクエストに一意のURLを与えることもできます。 URLハッシュには、AJAX履歴を作成するうえで非常に有利な点が2つあります。その1つは、現在のURL内のハッシュを変更してもページの再ロードが起こらないことです。そのため、ページを変更せずに一意のURLを作成することができます。もう1つの利点は、ブラウザがもともとURLハッシュをページ履歴の一部として扱っていることです。つまり、URLハッシュに移動すると、ブラウザの履歴リストにエントリが追加されます。現在のURLのハッシュマークの後ろに明確なエントリを追加すれば、AJAXアプリケーションで標準的な前進/後退動作とブックマーク機能を再現するのに役立つ履歴トレールを作成できます。たとえば、次のようなURLハッシュを使って、検索アプリケーションの2つの結果ページを指すことができます。 http://searchserver/search.jsp?searchText=television#page=1 http://searchserver/search.jsp?searchText=television#page=2 これらのURLハッシュ( RSH(Really Simple History) AJAXのUI問題に注目し、AJAXベースのアプリケーションでブラウザのデフォルト動作を維持するための取り組みを行っているフレームワークがいくつかあります。その1つがRSH(Really Simple History)フレームワークです。このフレームワークは、 また、 DojoAJAXのナビゲーション問題のもう1つの解決策となるのがDojoです。DojoはWebアプリケーションが[戻る]ボタンと[進む]ボタンのクリックを捕捉し、ブラウザのロケーションフィールドにブックマーク用の一意のURLを設定できるようにします。 DojoはJavaScriptで書かれたオープンソースのDHTMLツールキットで、Webページ(またはJavaScriptをサポートする他の環境)に動的な機能を組み込むのに役立ちます。Dojoのコンポーネントを使用すると、Webサイトの使いやすさと応答性と機能性を高めることができます。Dojoでは、複雑なユーザーインターフェイスを容易に構築したり、対話的なウィジェットをすばやくプロトタイプ化したり、トランジションをアニメーション化したりできます。Dojoの低レベルのAPIと互換性レイヤは、移植可能なJavaScriptの記述やスクリプトの単純化に貢献します。さらに、そのイベントシステムや入出力API、汎用言語拡張は、強力なプログラミング環境の基盤となります。 dojo.undo.browserモジュールはブラウザの履歴へのアクセスを提供し、ユーザーがAJAXアプリケーションから出なくても[戻る]ボタンと[進む]ボタンをクリックできるようにします。このツールキットは[戻る]イベントと[進む]イベントが発生したときにコールバックメッセージを発行して、開発者にWebアプリケーションを適切に更新する機会を与えます。Dojoは隠されたIFRAMEを使ったり、ページURLのハッシュ部分に一意の値を追加したりすることで、ブラウザの履歴を生成します。 URLハッシュ形式に含まれるアプリケーション状態識別子を変更してもページの更新は行われないので、アプリケーションの状態を保持するにはURLハッシュを使用するのが理想的です。Dojoが生成する一意のハッシュ値はもともとブックマークをサポートしていますが、アプリケーション状態識別子としてもっと意味のある値を指定すれば、ブックマークの可読性を高めることができます。Dojoの状態オブジェクトはページの状態を表します。この状態オブジェクトは、ユーザーが[戻る]ボタンと[進む]ボタンをクリックしたときにコールバックを取得します。状態オブジェクトはdojo.undo.browserに直接登録するだけでなく、イベントをバインドする Dojoの設定dojo.undo.browserを使用するには次のようにします。
状態オブジェクトでは次の機能を定義する必要があります。
以下は非常に単純な状態オブジェクトの例です。 var state = { back: function() { alert("Back was clicked!"); }, forward: function() { alert("Forward was clicked!"); } }; ユーザーアクションの結果を表す状態オブジェクトを登録するには、次の呼び出しを使用します。 dojo.undo.browser.addToHistory(state); あるいは、 ブラウザのアドレスバー内のURLを変更するには、状態オブジェクトに 検索アプリケーション以下では、前述した検索アプリケーションの問題にDojoの履歴機能を適用する方法を実例で示します。図1は、検索アプリケーションのディレクトリ構造を示しています。 図1 検索アプリケーションのディレクトリ構造。サンプルの検索アプリケーションはこれらのフォルダを使用 ![]() 図2 単純な検索フォーム。ユーザーは検索テキストを入力してから[Search]ボタンをクリックする。これにより、サーバーにバックグラウンドリクエストが送られる ![]() ユーザーが検索をトリガするメインページ(searchMain.jsp、図2を参照)は、アプリケーションのルートフォルダに置かれています。「dojo」フォルダには、「dojo.js」などの標準Dojoファイルが含まれています。「script」フォルダには、検索アプリケーション用の特別なJavaScriptファイルとして、アプリケーション状態実装を定義する「HistoryTracker.js」と、 著者注
このサンプルアプリケーションではJSPを使用していますが、この例はどんなサーバーサイドテクノロジ(PHPやASPなど)を使用したとしても同様にうまく働きます。
図2のフォームを表すHTMLの <form name="searchForm" action="#"> <input type="text" name="searchTextElement"></input> <input type="button" name="Search" value="Search" onclick="performSearch( this.form.searchTextElement.value);"></input> </form> ここで、ボタンを表す 以下の function performSearch(searchTxt, pageNumber) { var bindUrl = "/dojoapp/doSearch.jsp"; if(searchTxt) { bindUrl += "?searchTxt=" + searchTxt ; if(pageNumber) { bindUrl += "&pageNumber=" + pageNumber; } dojo.io.bind({ url: bindUrl, load: function(type, data, evt){ dojo.undo.browser.addToHistory( new HistoryTracker(data, searchTxt, pageNumber, "searchContent")); dojo.byId("searchContent").innerHTML = data; } }); } } 図3 検索結果のダミー。ページの下部に検索結果が表示される。 ![]() 以下は検索結果を生成するコードです(doSearch.js)。 You have searched for: <%= request.getParameter("searchTxt") %> <br/> Showing page number: <%= (request.getParameter( "pageNumber") == null) ? "1" : request.getParameter( "pageNumber") %> <br/> <a href="javascript:performSearch( '<%= request.getParameter("searchTxt") %>', '<%= (request.getParameter("pageNumber") == null) ? "2" : (Integer.parseInt(request.getParameter( "pageNumber") ) + 1) %>');">View next set of results</a> これはページ番号と検索テキストのみを表示するダミーページです。このページには、次の検索結果セットを取得するためのアンカータグが含まれており、このタグの dojo.addOnLoad(handleBodyLoad); function handleBodyLoad() { var state = new HistoryTracker(null, null, null, "searchContent"); dojo.undo.browser.setInitialState(state); handleUrlHash(); } function handleUrlHash() { var urlHash = location.hash.substring(1); var searchText, pageNumber; if(urlHash && urlHash != '') { var hashParams = urlHash.split(";"); for (i = 0; i < hashParams.length; i++) { var temp = hashParams[i].split("="); if(temp && temp.length > 0) { switch(temp[0]) { case 'searchTxt': searchText = temp[1]; break; case 'pageNumber': pageNumber = temp[1]; break; } } } } if(searchText) { if(pageNumber) { performSearch(searchText, pageNumber); } else { performSearch(searchText, 1); } } } これで検索アプリケーションが完成しました。http://yourdomain/searchMain.jspというURLをブラウズすれば、検索ページを表示することができます。 メインフォームが表示されたところで検索テキスト(「What is Dojo」など)を入力すると、同じページに検索結果が表示されます(図4を参照)。 図4 検索結果。検索結果は検索フォームと同じページに表示される ![]() ページは変化しませんが、次のように、元のURLの末尾にURLハッシュが追加されていることがわかるでしょう。 http://localhost:8080/dojoapp/searchMain.jsp このURLハッシュには、searchTxtとpageNumberの値がセミコロンで区切られて含まれています。検索結果の「View next set of results」リンクをクリックすると、2番目の検索結果ページが表示されます。 ご覧のように、DojoはAJAXアプリケーションにブックマークおよび[戻る]ボタンと[進む]ボタンを考慮させることができます。サンプルアプリケーションで示したように、各ページに明確なURLハッシュを割り当てることにより、ブラウザの履歴が更新されます。このテクニックを使用すると[戻る]ボタンと[進む]ボタンが正しく機能するので、ユーザーは任意のページに簡単にブックマークを付けることができます。本稿のダウンロードサンプルにはサンプルアプリケーションのコードが収録されており、すぐに使用できる状態になっています。ここで紹介したアイデアを、読者自身のナビゲーション対応AJAXアプリケーションの基礎として利用してください。 著者紹介Gautam Kumar Singh(Gautam Kumar Singh)
大企業のWebアプリケーション開発に携わって4年以上の経験を持つソフトウェアエンジニア。現在はHCL Technologies, Indiaの主任エンジニアとして勤務。
関連記事 最新トップニュース
|
japan.internet.com 10周年記念
インターネットコムマーケティングセミナー ROI を最適化するパフォーマンスマーケティングの最前線 【12/16(水)13時〜 東京・赤坂】 申込はコチラ>>
|