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でまた復活しています。
- Can I use… Support tables for HTML5, CSS3, etc
http://caniuse.com/#feat=history
もし未対応のブラウザでもpushState、replaceStateなどを使いたいという要望があれば、History.jsでフォールバック対応ができます。
- browserstate/history.js · GitHub
https://github.com/browserstate/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サイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。