window.location.hashとwindow.historyでハマったこと

window.history.back()を使用して、前画面に戻るためのリンクを実装したのだが、そのリンクをクリックしても画面が元に戻らない。そんな質問をされて調べたのだが、大分ハマってしまったのでメモ。


まずは、期待通りに戻らないソース。

<script type="text/javascript" src="/javascript/lib/jquery-1.5.2.js"></script>
<script type="text/javascript">
$(function(){
	$("#backButton").click(function(){
		window.history.back();
	});
	$("#backLink").click(function(){
		window.history.back();
	});
});
</script>
<body>
<h1>hashについて</h1>
<input type="button" value="戻るボタン" id="backButton">
<a href="#" name="top" id="backLink">戻るリンク</a><br>
<a href="#1" name="next1">次点1</a><br>
<a href="#2" name="next2">次点2</a><br>
<a href="#3" name="next3">次点3</a><br>
</body>

上記ソースの場合、「戻るボタン」は正常に動作するが、「戻るリンク」は動作しない。次点1,次点2,次点3とクリックした後、「戻るボタン」を3回クリックすると、次点3,次点2,次点1の順に移動するが、「戻るリンク」をクリックしても全く移動しない。

ボタンとリンクの違いなのに何故・・・。実際の原因究明では、これほど単純化されておらず、自分で書いたソースでもないので、恥ずかしいことに原因究明に時間がかかってしまった。

下記ソースの場合、ボタンでもリンクでも期待通りに戻る。

<script type="text/javascript" src="/javascript/lib/jquery-1.5.2.js"></script>
<script type="text/javascript">
$(function(){
	$("#backButton").click(function(){
		window.history.back();
	});
	$("#backLink").click(function(){
		window.history.back();
        //リンクに付与されたhashがURLに追加されることを防ぐ
        return false;
	});
});
</script>
<body>
<h1>hashについて</h1>
<input type="button" value="戻るボタン" id="backButton">
<a href="#" name="top" id="backLink">戻るリンク</a><br>
<a href="#1" name="next1">次点1</a><br>
<a href="#2" name="next2">次点2</a><br>
<a href="#3" name="next3">次点3</a><br>
</body>

動作しない場合との違いは、たった1行。ボタンリンクをクリックした際に実行されるイベントハンドラの最後でreturn false;を実行している点。
これにより、デフォルトのイベント(この場合、クリックイベント)をキャンセルし、hashが変更されることを防いでいる。この戻るリンク、<a href="#">で囲っているため、アンカータグをクリックした場合、URLに#というhashが付与されてwindow.historyにリンク自体のURLが追加されてしまう。そのため、window.history.back()を実行しても、戻る先がリンク自体になってしまっていたのだ。

なお、return false;の代わりに、preventDefaultメソッドを使用した下記のソースでも同じ。

<script type="text/javascript" src="/javascript/lib/jquery-1.5.2.js"></script>
<script type="text/javascript">
$(function(){
	$("#backButton").click(function(){
		window.history.back();
	});
	$("#backLink").click(function(event){
		window.history.back();
        //リンクに付与されたhashがURLに追加されることを防ぐ
        event.preventDefault();
	});
});
</script>
<body>
<h1>hashについて</h1>
<input type="button" value="戻るボタン" id="backButton">
<a href="#" name="top" id="backLink">戻るリンク</a><br>
<a href="#1" name="next1">次点1</a><br>
<a href="#2" name="next2">次点2</a><br>
<a href="#3" name="next3">次点3</a><br>
</body>

実際には、下記で試せる。
http://wbs-newworld.appspot.com/hashStudy.html