【HTML5】HISTORY API「pushState/popState」を使って画面遷移しなくてもURLを変化させて、戻るボタンの挙動をカスタマイズする

こんにちは。
pushStatepopStateというHTML5 HISTORY APIをご存知でしょうか。

もともとhistory APIは前からあり、history.back();などでブラウザの戻ると同じ挙動をさせることができます。
今回はHTML5で追加されたpushStatepopStateに注目していきましょう。

よくAjaxなど、画面遷移を伴わずコンテンツなどの入れ替えを行う際に活用されています。

Facebookの例

※個人情報の観点からスクリーンショットがご用意できずすみません。

メッセージページでは左側にメッセージのやり取り相手の写真が並びます。
それらをクリックすることによってメインのやり取りが表示されていくことになります。

そのとき、URLを注目してみると…

https://www.facebook.com/messages/nagatasan

であったり、

https://www.facebook.com/messages/san.nagata

という風に変わっているのが分かります。
また、戻るボタンの挙動は、それらをちゃんと戻っていく動きです。

どうなってるの?

画面遷移を行う(index.htmlからpage.htmlにファイルを移動するなど)場合はブラウザのヒストリーとして残るのが標準です。そして戻るボタンはそのヒストリーを戻っていくわけです。

しかしながら画面遷移を行わない場合は、デフォルトでそのようなことをしてくれません。
なので、明示的に行う必要があるのです。

実際の実装コードをみていきます。

if( window.history && window.history.pushState ){
    window.history.pushState(state,title,url);
}

javascriptでAPIを操作します。

  1. まず最初のifではpushStateに対応しているかどうかを確認します。(モダンブラウザでないと、対応していないものもあり、その場合は別途JSなどで実装する方法があります)
  2. window.history.pushState(state,title,url);というところでURLの変更やStateの保存をしていきます。ノンプログラマの方には馴染みがないかもしれませんが、push/popはそもそもスタックという考え方で、データ格納/データ取り出しの後入れ先出しという理解で問題ないかと思います。
    • state:状態と関連付けされた情報を格納できます
    • title:タイトルです
    • url:ブラウザのバーに表示されるURLです(実際に遷移するわけではないので、関係のない値をいれてもリダイレクト等はできません)

という流れがpushStateの使い方になります。
これだけでもURLが変動していき、戻るボタンをするとそれぞれその履歴に応じて戻っていくことができます。

具体的な使い方

さて、それではどういったときに活用できるかご紹介します。
ここからはpopStateも使っていきます。

タブメニューがあるページ

ページ自体は遷移せず、タブメニューで情報整理をしているページってありますよね。
そんなときはタブ移動のclickイベントなどと合わせてpushStateを行い、戻るボタンではpopStateを用いて挙動を書くことになります。

$('tabMenu').click(function(){
    var nextTab = $(this).next();
    openTab(nextTab);
    window.history.pushState(nextTab,null);
});

$(window).on('popstate', function(jqevent) {
    var state = jqevent.originalEvent.state;
    if (state) {
        openTab(state);
    };
});

という感じです。popStateで戻るボタンのイベントを取得し、もしpushStateしていたものがあれば該当するタブを開きます。

画面遷移はしていないのに、タブの遷移を戻るボタンにひもづけることができますね。

※jQueryでサンプル書いてますが、ピュアJSでも書くことができます。

アンカーやハッシュタグ、パラメーターを使っているページ

こちらも考え方は同じですが、pushState第3引数:URLまで指定しています。

$('nextButton').click(function(){
    var nextContent = $(this).next();
    goContent(nextContent);
    window.history.pushState(nextTab,null,"#"+nextContent);
});

$(window).on('popstate', function(jqevent) {
    var state = jqevent.originalEvent.state;
    if (state) {
        goContent(state);
    };
});

#hogehogeの他に、?param=hogehogeなども可能ですね。
ハッシュタグの場合、hashchangeというものを使うこともできます。

まとめ

いかがでしたか?
ページは遷移していないにも関わらずコンテンツが大きく変動するイベントの場合、ついつい利用者としては戻るボタンクリック(Macであればスワイプであったり)をしてしまいがちです。

「あー、そこまで戻るつもりじゃなかったんだよ」という不満を生まないためにも、ユーザーに配慮した挙動を考えると、デキる実装なんじゃないでしょうか!

ちなみに今日は本ブログを書きながら、弊社サービス「universions」にて画面遷移しないけどコンテンツが変わっていくページに、取り入れてみました。

是非御覧ください。

フォローして続編をチェック

@universionsをフォロー