如何通过history.pushState获得有关历史记录更改的通知?

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

可悲的是,这意味着 无法再被 检测到这些调用。onhashchange

我的问题是:有没有可靠的方法(黑客?;))来检测网站何时使用?该规范没有说明任何有关引发的事件的信息(至少我找不到任何内容)。
我试图创建一个外观并用我自己的JavaScript对象替换,但它根本没有任何效果。history.pushStatewindow.history

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

更新:

这是一个jsfiddle(使用Firefox 4或Chrome 8),显示调用时未触发(或者我做错了什么?随意改进它!onpopstatepushState

更新 2:

另一个(侧面)问题是使用时没有更新(但我认为我已经在这里读到了这一点)。window.locationpushState


答案 1

5.5.9.1 事件定义

在某些情况下,在导航到会话历史记录条目时会触发 popstate 事件。

据此,当您使用时,没有理由触发popstate。但是像这样的事件会派上用场。因为它是一个宿主对象,你应该小心它,但 Firefox 在这种情况下似乎很不错。这段代码工作得很好:pushStatepushstatehistory

(function(history){
    var pushState = history.pushState;
    history.pushState = function(state) {
        if (typeof history.onpushstate == "function") {
            history.onpushstate({state: state});
        }
        // ... whatever else you want to do
        // maybe call onhashchange e.handler
        return pushState.apply(history, arguments);
    };
})(window.history);

你的jsfiddle变成

window.onpopstate = history.onpushstate = function(e) { ... }

你可以用同样的方式猴子补丁。window.history.replaceState

注意:当然,您可以简单地将onpushstate添加到全局对象中,您甚至可以通过添加/删除Listener使其处理更多事件


答案 2

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

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