HTML5 History APIで非同期通信時にURLを変更する方法

HTML5 History APIで非同期通信時にURLを変更する方法

店長

店長

popStateイベントで戻るボタンがクリックされたことを検出する

pushState()で非同期通信時に履歴を追加することができました。
しかし、現在の状態だと戻るボタンを押しても反応がありません。

//戻る・進むボタンがクリックされたとき
$(window).on('popstate', popstateHandler);

//戻る・進むボタンがクリックされたときに実行される関数
function popstateHandler(e){
    e.preventDefault();
    var currentPage = getCurrentPage();
    $pager.each(function(){
        var self = this;
        var page = $(self).attr('href');
        if(page === currentPage){
            changePager.apply(self);
        }
    });
    loadingData(BASE_PATH + currentPage);
}

そこで、ブラウザの戻る・進むボタンがクリックされた際のイベントを検出します。
イベントを検出するにはpopStateイベントを使用します。

 

$(function(){
    var BASE_PATH = '/history-api/data/';
    var request = null;
    var $pager = $('#pager').find('a');

    //ページャーをクリックしたとき
    $pager.on('click', clickHandler);
    //戻る・進むボタンがクリックされたとき
    $(window).on('popstate', popstateHandler);

    //クリックした際に実行される関数
    function clickHandler(e){
        e.preventDefault();
        var self = this;
        var page = $(self).attr('href');
        var currentPage = getCurrentPage();
        //クリックしたリンク先のURLと現在のURLが一致する場合は処理を終える
        if(page === currentPage){
            return;
        }
        //履歴の追加
        history.pushState(null, null, page);
        //ページャーの変更
        changePager.apply(self);
        //データをロードする
        loadingData(BASE_PATH + page);
    }
    
    //現在のページ名を取得する
    function getCurrentPage(){
      return location.pathname.split('/').pop();
    }

    //戻る・進むボタンがクリックされたときに実行される関数
    function popstateHandler(e){
        e.preventDefault();
        var currentPage = getCurrentPage();
        //ページャーの変更
        $pager.each(function(){
            var self = this;
            var page = $(self).attr('href');
            if(page === currentPage){
                changePager.apply(self);
            }
        });
        //データをロードする
        loadingData(BASE_PATH + currentPage);
    }

    //ページャーを変更する
    function changePager(){
      $pager.removeClass('is-current');
        $(this).addClass('is-current');
    }

    //データを取得する
    function loadingData(url){
        //requestを確認してはabort
        if(request){
            request.abort();
        }
        //データのロード
        request = $.ajax({
           type: 'GET',
           dataType: 'html',
           url: url
        }).done(function(data){
            $('#photo').html(data);
        });
    }
});

jQueryのonメソッドを使用してpopStateイベントを検出します。
イベントが発火したら現在のページ名を取得して、そのページのデータを取得します。一緒にページャーも変更します。

以上で完成です。

おまけ

HTML5 History APIには他にも機能があるので簡単にご紹介します。

replaceState

replaceState(state, title, url);

replaceStateは現在の履歴を置き換えることができます。
引数はpushStateと同じです。

replaceStateとpushStateの違いを調べるためのコードを、下記の通り書いてみました。

$(function(){
  var $replace = $('#replace');
  var $push = $('#push');
  var before = null;
  var after = null;
  var name = null;

  //replaceStateボタン
  $replace.on('click', function(){
    clickHandler(runReplaceState);
  });

  //pushStateボタン
  $push.on('click', function(){
    clickHandler(runPushState);
  });

  //クリック時実行する関数
  function clickHandler(callback){
    before = history.length;
    name = callback();
    after = history.length;
    alertDetial();
  }

  //pushState()を実行する
  function runPushState(){
    history.pushState(null, null, '#push');
    return 'pushState()';
  }

  //replaceState()を実行する
  function runReplaceState(){
    history.replaceState(null, null, '#push');
    return 'replaceState()';
  }

  //alert()を実行する
  function alertDetial(){
    alert(name + 'が実行されました。\nボタンを押す前の履歴の数は' + before + '\nボタンを押した後の履歴の数は' + after + 'です。');
  }
});

history.lengthで履歴の数を調べ、replaceStateを実行する前とした後の変化を調べます。

それぞれのボタンをクリックするとpushState、replaceStateが実行されます。
pushStateは履歴が追加されるので、実行する前と後の履歴の数が変わります。
replaceStateは履歴を置き換えるので、実行する前と後の履歴の数は変わりません。

history.state

pushStateとreplaceStateの第一引数のstateはhistoryオブジェクトで確認することができます。

replaceState('hoge', null, 'page1.html');
console.log(history.state); //hoge

ブラウザの対応状況について

残念ながらIE8、IE9はサポートしていません。
Androidはすこし不思議で、2.2、2.3では対応していたのですが、Android3から対応を取りやめしてしまい、そして4.2でまた復活しています。

もし未対応のブラウザでもpushState、replaceStateなどを使いたいという要望があれば、History.jsでフォールバック対応ができます。

History.jsでは、HTML5 History APIが使用可能か調べ、使用不可であればハッシュを使用して擬似的にStateを実装してくれます。

まとめ

いかがでしたでしょうか?
このような処理を行うことでユーザがよりサイトを使いやすくなる場面もあると思います。
非同期通信する際はHistory APIを使ってみてください。

 

【APIでできることを知ろう!】

WebAPIドキュメント作成サービス「Apiary」を使ってWebアプリ開発を高速化しよう

Instagram APIを取得してWebサイトと連携し、投稿写真を自動に掲載する方法

Web初心者でもGoogle Mapsをカスタマイズできるgmaps.jsでAPIを使い倒そう!

画像を解析して写真にタグ付けをするAPI「clarifai」のデモを試してみた

Node.jsからGoogle Analytics APIにアクセスし、GA情報を表示させよう

LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。

Webサイト制作の実績・料金を見る

この記事のシェア数

フロントエンドエンジニアの店長です。 LIGに入社と同時に店長(あだ名が)になりました。偉くはありません。 以前、某カフェで働いていました。 音楽とコーヒーが大好きです。よろしくお願いいたします。

このメンバーの記事をもっと読む