4

我正在构建一个使用 AJAX 和pushState/replaceState在非 JavaScript 后备(http://biologos.org/resources/find)之上的工具。基本上,它是一个搜索工具,它返回一个真实的 HTML 链接列表(单击一个链接会带您离开该工具)。

我正在使用onpopstate,因此用户可以浏览由pushState. 当从真实链接(不是用实际浏览器导航创建而是由实际浏览器导航创建的)导航返回时也会触发此事件。我不想让它在这里开火。pushState

所以这是我的问题:如何区分onpopstate来自pushState历史项目的事件与来自真实导航的事件?

我想做这样的事情:

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

  // otherwise do something

}

我试过onpopstate 处理程序 - ajax 后退按钮但没有运气:(

提前致谢!

编辑: 这里的一个问题是不同浏览器处理onpopstate事件的方式。以下是似乎正在发生的事情:

铬合金

  • 触发onpopstate真实和虚拟事件_
  • 实际上重新运行javascript(所以设置loaded=false实际上会测试为假)
  • 上面链接中的解决方案确实有效!

火狐

  • onpopstate虚拟事件上触发
  • 实际上重新运行javascript(所以设置loaded=false实际上会测试为假)
  • 要使链接的解决方案真正起作用,loaded需要在页面加载时设置为 true,这会破坏 Chrome!

苹果浏览器

  • 触发onpopstate真实和虚拟事件_
  • 似乎不会在事件之前重新运行 javascript(loaded如果之前设置为 true,则为 true!)

希望我只是错过了一些东西......

4

1 回答 1

3

您也许可以使用history.js。它应该为您提供一个在所有主要平台上都表现一致的 API(尽管它可能无法解决这个特定问题;您必须尝试找出答案)。

但是,在我看来,处理这个(以及其他相关问题)的最佳方法是设计您的应用程序,使这些问题无关紧要。自己跟踪应用程序的状态,而不是完全依赖历史堆栈中的状态对象。

跟踪您的应用程序当前显示的页面。在一个变量中跟踪它——与window.location. 当导航事件(包括 popstate)到达时,将您的 knowncurrent page与请求的next page. 首先确定是否确实需要更改页面。如果是这样,则呈现请求的页面,并在必要时调用 pushState(仅调用 pushState 进行“正常”导航——从不响应 popstate 事件)。

处理 popstate 的相同代码也应该处理您的正常导航。就您的应用程序而言,应该没有区别(除了普通导航包含对 pushState 的调用,而 popstate 驱动的导航则不包含)。

这是代码中的基本思想(参见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包含当前可见页面的路径名。

于 2012-11-01T15:13:41.387 回答