现在HTML5引入了历史。pushState来改变浏览器的历史记录,网站开始与Ajax结合使用,而不是改变URL的片段标识符。

不幸的是,这意味着onhashchange再也不能检测到这些调用了。

我的问题是:有没有可靠的方法(hack?);))来检测网站何时使用history.pushState?规范没有说明引发的任何事件(至少我没有找到任何事件)。 我试图创造一个立面,并替换了窗户。我自己的JavaScript对象的历史,但它根本没有任何影响。

进一步解释:我正在开发一个Firefox插件,它需要检测这些变化并采取相应的行动。 我知道几天前有一个类似的问题,问监听一些DOM事件是否有效,但我宁愿不依赖于它,因为这些事件可以出于许多不同的原因生成。

更新:

这里是一个jsfiddle(使用Firefox 4或Chrome 8),显示onpopstate没有触发pushState被调用(或我做错了什么?请随意改进!)。

更新2:

另一个问题是那个窗口。使用pushState时,location不会更新(但我已经在这里读到这个,所以我认为)。


当前回答

我不认为这是一个好主意,即使你可以修改本机函数,你应该始终保持你的应用程序范围,所以一个好的方法是不使用全局pushState函数,而是使用你自己的一个:

function historyEventHandler(state){ 
    // your stuff here
} 

window.onpopstate = history.onpushstate = historyEventHandler

function pushHistory(...args){
    history.pushState(...args)
    historyEventHandler(...args)
}
<button onclick="pushHistory(...)">Go to happy place</button>

请注意,如果任何其他代码使用本机pushState函数,则不会获得事件触发器(但如果发生这种情况,则应该检查代码)

其他回答

标准状态如下:

注意,仅仅调用history.pushState()或history.replaceState()不会触发popstate事件。popstate事件仅由浏览器操作触发,例如单击后退按钮(或在JavaScript中调用history.back())

我们需要调用history.back()来触发WindowEventHandlers.onpopstate

所以不是:

history.pushState(...)

do:

history.pushState(...)
history.pushState(...)
history.back()

我用简单的代理来做到这一点。这是原型的替代方案

window.history.pushState = new Proxy(window.history.pushState, {
  apply: (target, thisArg, argArray) => {
    // trigger here what you need
    return target.apply(thisArg, argArray);
  },
});

除了其他答案。我们可以使用History接口,而不是存储原始函数。

history.pushState = function()
{
    // ...

    History.prototype.pushState.apply(history, arguments);
}

我不认为这是一个好主意,即使你可以修改本机函数,你应该始终保持你的应用程序范围,所以一个好的方法是不使用全局pushState函数,而是使用你自己的一个:

function historyEventHandler(state){ 
    // your stuff here
} 

window.onpopstate = history.onpushstate = historyEventHandler

function pushHistory(...args){
    history.pushState(...args)
    historyEventHandler(...args)
}
<button onclick="pushHistory(...)">Go to happy place</button>

请注意,如果任何其他代码使用本机pushState函数,则不会获得事件触发器(但如果发生这种情况,则应该检查代码)

你可以绑定到窗户上。onpopstate事件吗?

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

从文档中可以看出:

popstate的事件处理程序 事件。 对象的popstate事件被分派到 窗口每次激活历史记录 输入的变化。如果历史记录条目 被激活是由呼叫创建的 到history.pushState()或被影响 通过调用history.replaceState(), popstate事件的状态属性 包含历史记录项的副本 状态对象。