190

HTML5 でブラウザーの履歴を変更する機能が導入された今history.pushState、Web サイトは URL のフラグメント識別子を変更する代わりに、これを Ajax と組み合わせて使用​​し始めています。

悲しいことに、これらの呼び出しは では検出できなくなりましたonhashchange

私の質問は:ウェブサイトがいつ使用するかを検出する信頼できる方法 (ハック? ;)) はありhistory.pushStateますか? 仕様には、発生するイベントについては何も記載されていません (少なくとも、何も見つかりませんでした)。
ファサードを作成window.historyし、独自の JavaScript オブジェクトに置き換えようとしましたが、まったく効果がありませんでした。

詳細な説明:これらの変更を検出し、それに応じて動作する必要がある Firefox アドオンを開発しています。数日前に、いくつかのDOM イベント
をリッスンすることが効率的かどうかを尋ねる同様の質問があったことは知っていますが、これらのイベントはさまざまな理由で生成される可能性があるため、それに頼りたくはありません。

アップデート:

onpopstateが呼び出されたときにトリガーされないことを示すjsfiddle (Firefox 4 または Chrome 8 を使用) を次に示しますpushState(または、何か間違ったことをしていますか? 自由に改善してください!)。

更新 2:

別の(サイド)問題はwindow.location、使用時に更新されないことですpushState(ただし、これについてはすでにここで読んだと思います)。

4

16 に答える 16

229

5.5.9.1 イベント定義

特定のケースでは、セッション履歴エントリに移動するときにpopstateイベントが発生します。

これによると、使用時に popstate が発生する理由はありませんpushState。しかし、そのようなイベントpushstateは重宝します。historyはホスト オブジェクトなので注意が必要ですが、この場合は Firefox が良さそうです。このコードは問題なく動作します:

(function(history){
    var pushState = history.pushState;
    history.pushState = function(state) {
        if (typeof history.onpushstate == "function") {
            history.onpushstate({state: state});
        }
        // ... whatever else you want to do
        // maybe call onhashchange e.handler
        return pushState.apply(history, arguments);
    };
})(window.history);

あなたのjsfiddleは次のようになります:

window.onpopstate = history.onpushstate = function(e) { ... }

window.history.replaceState同じ方法でモンキーパッチを適用できます。

注: もちろん、onpushstate単純にグローバル オブジェクトに追加することもできます。add/removeListener

于 2011-01-03T13:59:56.747 に答える
5

私はこれを使用していました:

var _wr = function(type) {
    var orig = history[type];
    return function() {
        var rv = orig.apply(this, arguments);
        var e = new Event(type);
        e.arguments = arguments;
        window.dispatchEvent(e);
        return rv;
    };
};
history.pushState = _wr('pushState'), history.replaceState = _wr('replaceState');

window.addEventListener('replaceState', function(e) {
    console.warn('THEY DID IT AGAIN!');
});

ガランバラズがやったのとほぼ同じです。

普通にやり過ぎですけどね。また、すべてのブラウザーで機能するとは限りません。(ブラウザのバージョンだけが気になります。)

(そして、それは var_wrを残すので、ラップするか何かしたいかもしれません。私はそれを気にしませんでした。)

于 2014-09-04T19:54:18.890 に答える
2

ネイティブの履歴メソッドを上書きしたくないので、この単純な実装では、イベントをディスパッチして history.pushState() を返すだけの eventedPush 状態という独自の関数を作成します。どちらの方法でも問題なく動作しますが、将来の開発者が期待するようにネイティブ メソッドが引き続き機能するため、この実装は少しクリーンだと思います。

function eventedPushState(state, title, url) {
    var pushChangeEvent = new CustomEvent("onpushstate", {
        detail: {
            state,
            title,
            url
        }
    });
    document.dispatchEvent(pushChangeEvent);
    return history.pushState(state, title, url);
}

document.addEventListener(
    "onpushstate",
    function(event) {
        console.log(event.detail);
    },
    false
);

eventedPushState({}, "", "new-slug"); 
于 2020-01-28T10:13:24.203 に答える
1

あなたは Firefox アドオンについて尋ねているので、ここに私が作業したコードがあります。使用unsafeWindow推奨されなくなり、変更後にクライアント スクリプトから pushState が呼び出されるとエラーが発生します。

プロパティ history.pushState へのアクセスが拒否されました

代わりに、次のように関数を注入できるexportFunctionwindow.historyという API があります。

var pushState = history.pushState;

function pushStateHack (state) {
    if (typeof history.onpushstate == "function") {
        history.onpushstate({state: state});
    }

    return pushState.apply(history, arguments);
}

history.onpushstate = function(state) {
    // callback here
}

exportFunction(pushStateHack, unsafeWindow.history, {defineAs: 'pushState', allowCallbacks: true});
于 2015-08-27T21:34:05.720 に答える
0

window.onpopstateイベントにバインドできますか?

https://developer.mozilla.org/en/DOM%3awindow.onpopstate

ドキュメントから:

ウィンドウの popstate イベントのイベント ハンドラー。

アクティブな履歴エントリが変更されるたびに、popstate イベントがウィンドウにディスパッチされます。アクティブ化されている履歴エントリが history.pushState() の呼び出しによって作成された場合、または history.replaceState() の呼び出しによって影響を受けた場合、popstate イベントの状態プロパティには履歴エントリの状態オブジェクトのコピーが含まれます。

于 2011-01-02T23:18:10.397 に答える
0

新しい URL が欲しかったので、@gblazex と @Alberto S. のコードを適用してこれを取得しました。

(function(history){

  var pushState = history.pushState;
    history.pushState = function(state, key, path) {
    if (typeof history.onpushstate == "function") {
      history.onpushstate({state: state, path: path})
    }
    pushState.apply(history, arguments)
  }
  
  window.onpopstate = history.onpushstate = function(e) {
    console.log(e.path)
  }

})(window.history);
于 2020-06-22T01:36:38.600 に答える