4

私は AJAX を使用するツールを構築してpushStateます。基本的に、これは実際の HTML リンクのリストを返す検索ツールです (リンクをクリックするとツールが終了します)。replaceState

onpopstateによって作成されたクエリ履歴をユーザーがナビゲートできるように使用していますpushState。このイベントは、実際のリンク (作成されたのではなく、実際のブラウザー ナビゲーションによって作成されたリンク) から戻ったときに発生します。ここで炎上させたくない。pushState

onpopstateでは、私の質問は次のとおりです。履歴アイテムからのイベントpushStateと実際のナビゲーションからのイベントの違いをどのように見分けることができますか?

私はこのようなことをしたい:

window.onpopstate = function(event){
  if(event.realClick) return;

  // otherwise do something

}

onpopstate ハンドラー - ajax 戻るボタンを試しましたが、運がありません:(

前もって感謝します!

編集: ここでの問題は、さまざまなブラウザーがonpopstateイベントを処理する方法です。これが起こっているようです:

クロム

  • 実際のイベントと仮想イベントのonpopstate両方で発生します
  • 実際にJavaScriptを再実行します(設定loaded=falseは実際にはfalseをテストします)
  • 上記のリンクのソリューションは実際に機能します!

ファイアフォックス

  • 仮想イベントでのみ発生onpopstateします
  • 実際にJavaScriptを再実行します(設定loaded=falseは実際にはfalseをテストします)
  • リンクされたソリューションが実際に機能するにはloaded、ページの読み込み時に true に設定する必要があります。これにより、Chrome が壊れます。

サファリ

  • 実際のイベントと仮想イベントのonpopstate両方で発生します
  • イベントの前に JavaScript を再実行しないloadedようです (したがって、以前に true に設定されていれば true になります!)

うまくいけば、私は何かが足りないだけです...

4

1 に答える 1

3

history.jsを使用できる場合があります。すべての主要なプラットフォームで一貫して動作する API を提供する必要があります (ただし、この特定の問題に対処していない可能性があります。確認するには試してみる必要があります)。

ただし、私の意見では、これ (およびその他の関連する問題) を処理する最善の方法は、これらの問題が問題にならないようにアプリケーションを設計することです。履歴スタック内の状態オブジェクトだけに依存するのではなく、自分でアプリケーションの状態を追跡します。

アプリケーションが現在表示しているページを追跡します。とは別の変数で追跡しますwindow.location。ナビゲーション イベント (popstate を含む) が到着したら、既知current pageの と要求された を比較しますnext page。ページの変更が実際に必要かどうかを判断することから始めます。その場合は、要求されたページをレンダリングし、必要に応じて pushState を呼び出します (「通常の」ナビゲーションの場合にのみ pushState を呼び出します。popstate イベントに応答することはありません)。

popstate を処理する同じコードで、通常のナビゲーションも処理する必要があります。アプリケーションに関する限り、違いはありません (通常の nav には pushState の呼び出しが含まれますが、popstate 駆動の nav には含まれません)。

コードの基本的な考え方は次のとおりです ( jsBin の実際の例を参照してください) 。

// keep track of the current page.
var currentPage = null;

// This function will be called every time a navigation
// is requested, whether the navigation request is due to
// back/forward button, or whether it comes from calling
// the `goTo` function in response to a user's click... 
// either way, this function will be called. 
// 
// The argument `pathToShow` will indicate the pathname of
// the page that is being requested. The var `currentPage` 
// will contain the pathname of the currently visible page.
// `currentPage` will be `null` if we're coming in from 
// some other site.
// 
// Don't call `_renderPage(path)` directly.  Instead call
// `goTo(path)` (eg. in response to the user clicking a link
// in your app).
//
function _renderPage(pathToShow) {
  if (currentPage === pathToShow) {
    // if we're already on the proper page, then do nothing.
    // return false to indicate that no actual navigation 
    // happened.
    //
    return false;
  }

  // ...
  // your data fetching and page-rendering 
  // logic goes here
  // ...

  console.log("renderPage");
  console.log("  prev page  : " + currentPage);
  console.log("  next page  : " + pathToShow);

  // be sure to update `currentPage`
  currentPage = pathToShow;

  // return true to indicate that a real navigation
  // happened, and should be stored in history stack
  // (eg. via pushState - see `function goTo()` below).
  return true;
}

// listen for popstate events, so we can handle 
// fwd/back buttons...
//
window.addEventListener('popstate', function(evt) {
  // ask the app to show the requested page
  // this will be a no-op if we're already on the
  // proper page.
  _renderPage(window.location.pathname);
});

// call this function directly whenever you want to perform
// a navigation (eg. when the user clicks a link or button).
// 
function goTo(path) {

  // turn `path` into an absolute path, so it will compare
  // with `window.location.pathname`. (you probably want
  // something a bit more robust here... but this is just 
  // an example).
  //
  var basePath, absPath;
  if (path[0] === '/') {
    absPath = path;
  } else {
    basePath = window.location.pathname.split('/');
    basePath.pop();
    basePath = basePath.join('/');    
    absPath = basePath + '/' + path;
  }

  // now show that page, and push it onto the history stack.
  var changedPages = _renderPage(absPath);
  if (changedPages) {
    // if renderPage says that a navigation happened, then
    // store it on the history stack, so the back/fwd buttons
    // will work.
    history.pushState({}, document.title, absPath);
  }
}

// whenever the javascript is executed (or "re-executed"), 
// just render whatever page is indicated in the browser's 
// address-bar at this time.
//
_renderPage(window.location.pathname);

jsBinの例を確認する_renderPageと、アプリが新しいページへの遷移を要求するたびに関数が呼び出されることがわかりますpopstategoTo(page)たとえば、ある種のユーザー アクション)。ページが最初に読み込まれたときにも呼び出されます。

あなたのロジックは、_renderPage関数内での値を使用して、currentPage「リクエストがどこから来ているか」を判断できます。外部サイトから来ている場合は にcurrentPageなりますnull。それ以外の場合は、現在表示されているページのパス名が含まれます。

于 2012-11-01T15:13:41.387 に答える