web-dev-qa-db-ja.com

ウィンドウバインドPOPSTATE

次の場合:

$(window).bind("popstate", function() {
    alert('popstate');
});

最初の読み込み時に、FireFoxとChrome=でアラートが発生しますが、Safariでは発生しません。なぜですか?これを他の誰かが見て、これを解決する最善の方法を知っていますか?

29
AnApprentice

状況は逆転した。 Chromeはバグを修正し、ページのロード時にpopstateを起動しますが、Firefox 4(RC以降)は仕様から逸脱し、- popstateを起動しません

[〜#〜] update [〜#〜]:HTML5仕様は2011年に変更され、ページのロード時にpopstateが呼び出されないようになりました。 FirefoxとChromeはFirefox 4と Chrome 34 のように正しく動作するようになりました。

15
Tamlyn

Pjaxのコードを参照してください。現在、pjaxはかなり人気のあるオープンソースライブラリです。そのため、この問題を回避するには、以下のロジックが最適です。

var popped = ('state' in window.history), initialURL = location.href
$(window).bind('popstate', function(event) {
  // Ignore inital popstate that some browsers fire on page load
  var initialPop = !popped && location.href == initialURL
  popped = true
  if ( initialPop ) return
  ...

https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js

45
Nobu

Webkitでは、ページの読み込み時にpopstateイベントが発生します。これを回避するために、この簡単な回避策は私にとってはうまくいきます:

history.Push(...)を呼び出すたびに、class-タグにbodyhistorypushedを追加します。

history.Push(...);
$("body").addClass("historypushed");

Popstateイベントをトリガーするときに、このクラスを確認します。

$(window).bind('popstate', function(e) {
 if($("body").hasClass("historypushed")) { 
  /* my code */ 
 } 
});
17
lohsie

この問題を回避する簡単な方法は、pushStateの最初の引数をtrueに設定してから、onpopstateをチェックすることです。 pjaxの例に似ていますが、もう少し簡単です。以下の例では、最初のページのロードを除くすべてのpopstateイベントに対してdoSomething()を実行します。

function setupPopState() {
  if (history.popState) {
    # immediately replace state to ensure popstate works for inital page
    history.replaceState(true, null, window.location.pathname);

    $(window).bind('popstate', function(event) {
      if (event.originalEvent.state) {
        doSomething();
      }
    });
  }
}
3
HuffMoody

Webkitには、「popstate」イベントを誤って実装するバグがありました。問題を説明するこの簡単な投稿をチェックしてください(クールな小さなショーと教え): http://www.bcherry.net/playground/pushstate

私の提案は、Safariに独自の「popstate」イベントトラッカーを実装することです。このようなもの:

$(window).load(function(){
  function fire_popstate(){
    $(this).trigger("popstate"); // fire it when the page first loads
  }
  var lasthash = window.location.hash;
  setInterval(function(){
    var currenthash = window.location.hash;
    if(lasthash != currenthash){
      fire_popstate();
    }
  }, 500);//check every half second if the url has changed
});

そのステートメントをブラウザのテストにラップして、サファリをチェックすることができます。 DOMの準備ができるまでに「popstate」が起動されているかどうかを確認し、内部関数を適用して実装を置き換えます。発生させたくないのは、2つのpopstateイベントを発生させることです(UIをロックするための優れた方法である、イベントハンドラーロジックの複製)。

2
Shakakai

これが私の回避策です。

window.setTimeout(function() {
  window.addEventListener('popstate', function() {
    // ...
  });
}, 1000);
0
Baggz

同様の質問に対するこの回答は、popstateイベントハンドラーでevent.stateの真偽をチェックすることを提案しています:

window.addEventListener('popstate', function(event) {
    if (event.state) {
        alert('!');
    }
}, false);

次のように、コールバック関数をpopstateイベントに関連付けることもできます。

window.onpopstate = callback();

その解決策の詳細については、ここを確認してください

0
Wilt

@Nobuと@Tamlynの回答をオブジェクトに変換し、「window.history.state!== null」を追加することで、少し修正を加えます。一部のブラウザでは、history.stateが存在しますが、nullであるため、機能していませんでした。

/**
 * The HTML5 spec was changed in 2011 to state popstate should not 
 * fired on page load. Chrome(34) & Firefox(4) has fixed the bug but 
 * some browsers (e.g. Safari 5.1.7) are still fire the popstate on
 * the page load. This object created from the Pjax Library to handle 
 * this issue.
 */
var popstatePageloadFix = {
        popped : ('state' in window.history && window.history.state !== null),
        initialUrl : location.href,
        initialPop : false,
        init : function() {
                this.initialPop = !this.popped && location.href == this.initialUrl;
                this.popped = true;
                return this.initialPop;
        }
};

$(window).on("popstate", function (event) {
        
        // Ignore initial popstate that some browsers fire on page load
        if ( popstatePageloadFix.init() ) return;
        
        ...

});

ありがとう@Nobu!ありがとう@Tamlyn!

0
Roy Shoa