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
と、アプリが新しいページへの遷移を要求するたびに関数が呼び出されることがわかりますpopstate
。goTo(page)
たとえば、ある種のユーザー アクション)。ページが最初に読み込まれたときにも呼び出されます。
あなたのロジックは、_renderPage
関数内での値を使用して、currentPage
「リクエストがどこから来ているか」を判断できます。外部サイトから来ている場合は にcurrentPage
なりますnull
。それ以外の場合は、現在表示されているページのパス名が含まれます。