1. ホーム
  2. ジャバスクリプト

[解決済み】ブラウザの戻るボタンのイベントを検出する方法 - クロスブラウザ編

2022-03-30 13:04:17

質問

ユーザーがブラウザの戻るボタンを押したかどうかを確定的に検出するにはどうすればよいですか?

単一ページのウェブアプリケーションで、ページ内戻るボタンを強制的に使用するには #URL の仕組みを教えてください。

ブラウザの戻るボタンは、なぜ独自のイベントを発生させないのですか!?

解決するには?

(注:Sharkyのフィードバックにより、バックスペースを検出するコードを含めました)

SOでは、このような質問をよく見かけますが、最近、私自身も戻るボタンの機能を制御する問題に直面しました。私のアプリケーション(ハッシュナビゲーションを持つシングルページ)に最適なソリューションを数日間探した結果、戻るボタンを検出するためのシンプルでクロスブラウザ、ライブラリ不要のシステムを思いつきました。

ほとんどの人が使用を推奨しています。

window.onhashchange = function() {
 //blah blah blah
}

しかし、この関数は、ユーザーがページ内要素でロケーションハッシュを変更したときにも呼び出されます。ユーザーがクリックしたときにページが前後するのは、最良のユーザーエクスペリエンスとは言えません。

私のシステムの概要を説明すると、ユーザーがインターフェイス内を移動するたびに、以前のハッシュを配列に詰めています。それは次のようなものです。

function updateHistory(curr) {
    window.location.lasthash.push(window.location.hash);
    window.location.hash = curr;
}

かなりわかりやすい。クロスブラウザのサポートと古いブラウザのサポートを確実にするためにこうしているのです。新しいハッシュを関数に渡すだけで、関数がそれを保存し、ハッシュを変更します(ブラウザの履歴に入れられます)。

また、ページ内の戻るボタンを利用して、ユーザーをページ間で移動させるために lasthash の配列があります。以下のような感じです。

function goBack() {
    window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
    //blah blah blah
    window.location.lasthash.pop();
}

つまり、これはユーザーを最後のハッシュに戻し、その最後のハッシュを配列から削除します(今、私は進むボタンを持っていません)。

では、ユーザーがページ内の戻るボタンやブラウザのボタンを使用したかどうかを検出するにはどうすればよいのでしょうか?

最初、私は window.onbeforeunload これは、ユーザーがページを変更する場合にのみ呼び出されます。これは、ハッシュナビゲーションを使用した単一ページのアプリケーションでは起こりません。

そこで、さらに調べてみると、フラグ変数を設定することを推奨していることがわかりました。私の場合の問題は、設定しようとしても、すべてが非同期なので、ハッシュの変更のif文に間に合うように設定できるとは限らないということです。 .onMouseDown は常にクリックで呼び出されるわけではなく、onclickに追加しても十分な速さで発動することはありませんでした。

という違いに注目し始めたのがきっかけです。 documentwindow . 私の最終的な解決策は、フラグを設定するために document.onmouseover を使用し、無効化するには document.onmouseleave .

ユーザーのマウスがドキュメント領域(レンダリングされたページ、ただしブラウザーのフレームは除く)にあるとき、私のブーリアンは次のように設定されます。 true . マウスがドキュメントエリアから離れるとすぐに、ブール値は false .

こうすることで、私の window.onhashchange に変更します。

window.onhashchange = function() {
    if (window.innerDocClick) {
        window.innerDocClick = false;
    } else {
        if (window.location.hash != '#undefined') {
            goBack();
        } else {
            history.pushState("", document.title, window.location.pathname);
            location.reload();
        }
    }
}

のチェックに注目です。 #undefined . これは、もし私の配列の中に利用可能な履歴がなければ、それは undefined . 私はこれを使って、ユーザーに退出するかどうかを window.onbeforeunload イベントが発生します。

つまり、必ずしもページ内の戻るボタンや履歴を保存するための配列を使用していない人のために、このようになります。

document.onmouseover = function() {
    //User's mouse is inside the page.
    window.innerDocClick = true;
}

document.onmouseleave = function() {
    //User's mouse has left the page.
    window.innerDocClick = false;
}

window.onhashchange = function() {
    if (window.innerDocClick) {
        //Your own in-page mechanism triggered the hash change
    } else {
        //Browser back button was clicked
    }
}

ハッシュ・ナビゲーションに関して、戻るボタンの使用とページ内要素を検出するためのシンプルな3つの方法です。

EDIT

ユーザーが backspace を使って back イベントをトリガーしないようにするには、次のように記述することもできます(Thanks to @thetoolman on この質問 ):

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});