この記事では、JavaScriptを使用したこのような便利なナビゲーションメカニズムの実装について説明します。
どうだった...
従来のHTMLでは、URIフラグメントを使用して、大きなドキュメント内で簡単なナビゲーションを作成しました。 ドキュメントの適切な場所に、フォームのタグ(いわゆるアンカー)を挿入し、Go Hereタイプのリンクを使用してそれらを参照できます。 このようなリンクをクリックすると、ブラウザはページをリロードせずにドキュメントを適切な場所にスクロールしました。 新しいウィンドウでsite.com/path/to/doc.html#go-hereリンクを開くことも可能で、ドキュメントをロードした後、ブラウザはアンカー位置から自動的にそれを表示しました。 当然、アンカーはこの機能をサポートするブラウザでのみ機能しました。 フラグメントの処理は、完全かつ完全にクライアント側に移行しました。 URIフラグメントはWebサーバーにも送信されませんでした(現在は送信されていません)。
...そして今
ご覧のとおり、フラグメントには2つの重要な利点があります。
- フラグメント間の遷移はページのリロードを引き起こしません
- 標準のクエリ文字列と同様に、これらは直接リンクとして使用でき、ユーザーは遷移が発生した(アドレスバーが変更された)ことを視覚的に確認できるため、それらをコピーして誰かに送信すると便利です。
今日、DHTMLおよびAJAXテクノロジーの勝利の行進の時代に、フラグメントはこれらの2つの注目すべき特性のおかげで新しい命を獲得しました。 URIフラグメントのアドレス指定により、ページをリロードすることなく、AJAXで完全に動作するRIAアプリケーションを構築でき、同時に通常のWebアプリケーションの通常の機能の一部を保持できます。 つまり、リンクに特定の状態(オープンレター/写真/ドキュメント)を保存し、このリンクを開いた別のユーザーに転送すると、あなたと同じものが表示されます。
実用的な例。
クライアントの1人が、サイトのJavascriptスライドショーフォトギャラリーを注文しました。 写真間の遷移によってページがリロードされることはありませんが、同時に特定の写真へのリンクをコピーして送信する機会を求めました。 この問題は、フラグメントアドレッシングを使用して簡単に解決できました。
写真へのリンクはsite.com/gallery/name-of-gallery/#photo_idのように見えました。ここで、photo_idは画像コードです。 カルーセルのサムネイルと同様に、進むボタンと戻るボタンは、対応する写真のコードを含むフラグメントへの通常のリンクでした。 サムネイルスライドショーコンポーネントとカルーセルは、URIフラグメントの変更イベントをインターセプトし、それに応じて反応しました(スライドショーは目的の写真を表示し、カルーセルはそれにスクロールしてフレームで強調表示しました)。 また、作成後すぐに、これらの各コンポーネントは現在のフラグメントをチェックし、写真に移行しました。
アプリケーションを編成するこの原則は非常に便利です。 そのコンポーネントは、状態の変化を追跡するために互いのイベントハンドラに「固執」する必要はありません。 誰でもすぐにURIフラグメントの変更を監視し、必要なアクションを実行するだけで十分です。 多くの多対多の関係を持つシステムの代わりに、開発とデバッグがはるかに簡単な集中管理システムを取得します。
ExtJSで
ExtJSフレームワークは、フラグメントアドレッシングを操作するための便利なシングルトンExt.Historyを提供します。 それを使用する前に、する必要があります
- 非表示フィールドとiframeを持つ補助フォームを作成します。 標準のJavaScript機能では、現在のフラグメント(window.location.hash)のみを読み取ることができ、変更時に発生するイベントはありません。 それを追跡するために、Ext.Historyは現在のフラグメントを非表示フィールドに保存し(IEでiframeを使用)、タイマー関数を使用して定期的にチェックし、変更されたかどうかを確認します。
- init()メソッドを呼び出してシングルトンを初期化します。
次にサンプルコードを示します。
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
シングルトンの詳細なドキュメントは、 http://www.extjs.com/deploy/dev/docs/? class = Ext.Historyにあります 。 最も一般的に使用される機能について説明します。 Ext.Historyの用語では、フラグメントはトークンと呼ばれます。
- Ext.History.add(トークン)-現在のトークンを指定されたトークンに変更します。 これにより、このフラグメントへのハイパーテキストリンクをクリックしたかのように、アドレスバーのリンクが変更されます。
- Ext.History.getToken()-現在のトークンを取得します
- Ext.History.back()、Ext.History.forward()-ブラウザの[戻る]および[進む]ボタンをクリックするのと同じ
- イベントの変更(文字列トークン)-トークンが変更されたとき(リンクをクリックしたとき、またはaddメソッドが呼び出されたとき)にスローします。
使用例:
*このソースコードは、 ソースコードハイライターで強調表示されました。
- < スクリプト タイプ =” text / javascript ” >
- Ext.onReady( function (){
- <ExtHistoryの初期化(上記のコードを参照)>
- var showToken = function (token){
- if (Ext.isString(token)&& token!= '' )Ext.Msg.alert( 'Token changed' 、String.format( 'New token:{0}' 、token));
- }、
- t = Ext.History.getToken();
- Ext.History.on( 'change' 、showToken);
- Ext.get( 'settoken4' ).on( 'click' 、Ext.History.add.createDelegate(Ext.History、[ 'token4' ]、 false ));
- showToken(t);
- });
- </ スクリプト >
- <a href = "# token1">トークン1 </ a > | <a href = "# token2">トークン2 </ a > | <a href = "# token3">トークン3 </ a >
- < 入力 タイプ = "ボタン" 値 = "トークン4を設定" id = "settoken4" />
公式デモはリンクで見ることができます
http://www.extjs.com/deploy/dev/examples/history/history.html
そして、ここで与えられたコードの仕事の例はここにあります 。 サンプルのソースコードをダウンロードすることもできます(ExtJS配布なしの代替リンク )。
MooToolsで
標準のMooTools配信にはフラグメントのアドレス指定を扱うクラスがありませんでした。プラグインが見つからなかったため、Ext.Historyシングルトンを使用することにしました。 MooToolsに適合させるのに少し時間を要しました。 また、シングルトンを少し終了しました-init()メソッドで補助フォームの作成を組み込み、jsファイルが接続されたときにシングルトンを自動的に初期化します
Mootolls-singleton IはHistoryManagerと呼ばれます。 メソッドとイベントは、Ext.Historyのメソッドとイベントと完全に同一です。
使用例:
*このソースコードは、 ソースコードハイライターで強調表示されました。
- < スクリプト タイプ = "text / javascript" >
- window.addEvent( 'domready' 、 function (){
- var showToken = function (token){
- if ($ type(token)== 'string' && token!= '' )alert( '新しいトークン:{t}' .substitute({t:token}));
- }、
- t = HistoryManager.getToken();
- HistoryManager.addEvent( 'change' 、showToken);
- $( 'settoken4' ).addEvent( 'click' 、HistoryManager.add.bind(HistoryManager、[ 'token4' ]));
- showToken(t);
- });
- </ スクリプト >
- </ 頭 >
- < 本体 >
- <a href = "# token1">トークン1 </ a > | <a href = "# token2">トークン2 </ a > | <a href = "# token3">トークン3 </ a >
- < 入力 タイプ = "ボタン" 値 = "トークン4を設定" id = "settoken4" />
ここに示されているコードの動作の例は、デモフォトギャラリー- ここにあります 。 また、サンプル(ExtJS配布キットなしの代替リンク )とフォトギャラリーのソースコードをダウンロードすることもできます。
PS Ext.HistoryをPrototypeまたはjQueryに翻訳する必要がある場合-お問い合わせください。
UPD: JavaScriptに移植されたカルマをありがとう