HIDARI日記(右)

そのときどき興味ある技術を中心にだらだら書いてます。内容は個人の見解であり、所属する企業を代表するものではありません。

JavaScriptだけでブラウザの「戻る」ボタンを無効化する方法

このあいだ諸事情で調べたら、意外とまとまってるとこなかったなのでちょこっと書いてみます。

  • IE8以降を対象
  • ブラウザの「戻る」ボタンで他のページに遷移しない
  • Backspaceキーでの「戻る」も許可しない

みたいな方針で調べてみました。

まあ結論から言うと

Ah, the back button. You might imagine "back" fires a JavaScript event which you could simply cancel like so:

document.onHistoryGo = function() { return false; }

No so. There simply is no such event.

javascript - Intercepting call to the back button in my AJAX application: I don't want it to do anything! - Stack Overflow

というわけで、ブラウザの戻るボタンをお手軽に無効にする方法はないようですね。

方法

1.window.onunloadイベントを利用する

まず直接的なイベントが無いなら似たようなイベントをかわりに使おう!みたいな安直な発想で。

ページから離れる際に発生するonunloadイベントをトリガーとして、次に表示されるページ(遷移先)を現在のページにしてしまう関数を実行する方法。

window.onunload = function() {
    alert('Back buttom is pushed ??');
    location.replace(document.location);
};  

onunloadは戻るボタン以外でも発生するの。Backspaceキー、URLの直接入力、履歴からの遷移でも。リンクをクリックしたときも当然発生する。その結果、このコードがあるページからは移動できなくなるという仕組み。

対象を「戻る」ボタンの動作だけに絞ることができないので、この方法はちょっと厳しそう。

以下のように、適当なタイミングでイベントハンドラを削除することで移動できるようにすることもできなくはないけど、釈然としない。

<script type="text/javascript">
    function goNextPage() {
        window.onunload = null;
    };
</script>

<a href="./Page3.html" onclick=" goNextPage(); ">Go Next</a>

というかIE11ではlocation.replace()でランタイムエラーになって動かないんだよな…(だめじゃん

参考:ブラウザの戻るボタンを無効にする方法: ある SE のつぶやき

2.history.forward()関数を使う

検索するとよく見つかる方法。遷移元のページに 以下のJSを記述しておく。

window.onunload = function() {};
history.forward();

上のコードがhead要素辺りに書いてあるページAからページBへ遷移、その後Bから「戻る」ボタンでAへ戻ると、history.foward()関数でBへ送り返されます。なので、Backspaceキー使われても平気。

ただ、履歴の一つ前がAのときはBからだけでなくどのページからも戻れないことになるので、特定のページだけ「戻る」ボタンを使用不可にしたい!みたいな状況では使えない。

逆にこのページだけには戻ってきてほしくない、っていうときは、あるいは使える?

参考:[JavaScript] ブラウザの戻るボタンを無効にする方法 | 自由が丘で働くWeb屋のブログ

3.window.location.hashを使う

URLにhash(URLの後ろにくっつく#HogeHogeみたいな文字列で、ページ内リンクなんかに使われてる)をつけることで別ページへの遷移として履歴に残して、他のページに戻れなくしてしまう方法。

window.location.hash="no-back";
window.location.hash="no-back-button";
window.onhashchange=function(){
    window.location.hash="no-back";
}

ページが読み込まれたタイミングでURLの末尾に#no-back、あるいは#no-back-buttonを追加し、同時にhashが変更されると発生するonhashchangeでhashを変更する関数を追加する。

ページに遷移してきた時点で、履歴の一つ前のページが自分自身になっているため、戻るボタンを押しても自分に戻るだけになるという寸法。

URLに余計な文字列が含まれてしまうのを嫌がる人もいますが、先に挙げた方法よりだいぶ安定している印象ですね。

参考:javascript - How to Detect Browser Back Button event - Cross Browser - Stack Overflow

4. history.go()を使う???

+JavaScript+ブラウザの戻るボタンの無効化 - Free Flying

こういう方法もあるみたいだけど、なんでhistory.go()で「戻る」が使えなくなるのかイマイチ分からなかったんで試すのをやめました。

参考:go method (Internet Explorer)

5. HTML5の History API を利用する

今回僕が当たった要件では難しいけど、HTML5が利用できるIE10以降では以下の方法を使えば、概ねそれらしく動きます。

「戻る」を禁止したいページに以下のJSを書く。

<script type="text/javascript">
    history.pushState(null, null, null);

    window.addEventListener("popstate", function() {
        history.pushState(null, null, null);
    });
</script>

ページが読み込まれたらhistory.pushState()メソッドで履歴の先頭に新しい履歴がひとつ追加される。このとき第3引数がnullなので、追加された履歴は自分自身を指していることになる。続いてpopstateイベントのハンドラとしてhistory.pushState()を実行する関数を指定する。

「戻る」ボタンが押されるとpopstateからイベントハンドラが実行され、自分自身を指す履歴(history.pushState(null, null, null))がもう一つ追加される。

ページ読み込み時に実行されるhistory.pushState()では、最初に「戻る」が実行されたときに戻る先の履歴が追加され、2回目以降の「戻る」実行時はイベントハンドラで追加される履歴が使用される、はず。

戻る先は常に自分自身になるため、結果として「戻る」ボタンを無効化できます。先に書いたlocation.hashに近いもので、実際リファレンスには

ある意味では、pushState() の呼び出しは window.location = "#foo"; と設定するのと似ています。どちらも、現在のドキュメントに関連する別の履歴エントリの生成とアクティベートを行います。

Manipulating the browser history - Web developer guide | MDN

とあるので、HTML5が使えるならhistory.pushState()、ダメならlocation.hashを使うというのが、ある意味正攻法なのかも。

まあ、各種イベントの発火条件とかに違いがあるので、よく考えて使う必要があるのは言うまでもないのですが。

参考:

おわりに

かろうじて使えるかなって言うのがlocation.hashを使う方法でしょうか。

というかそもそもですね、特にレガシーな感じのブラウザで、「戻る」ボタンの無効化くらいJavaScriptだけでできるんでしょ?ちゃちゃっとやっちゃって?という、(冒頭の引用のような)安直な考えは捨てるべきなのではとか思わずにはいられないと思ったり思わなかったり。