如何检查URL是否在JavaScript中发生了变化?例如,像GitHub这样使用AJAX的网站,会在#符号后附加页面信息,以创建唯一的URL,而无需重新加载页面。检测该URL是否发生变化的最佳方法是什么?

是否再次调用onload事件? 是否有URL的事件处理程序? 或者必须每秒钟检查URL以检测更改?


当前回答

在一个单独的线程中找到了一个工作答案:

没有一个事件是永远有效的,对于大多数大型spa来说,monkey patch pushState事件是非常偶然的。

所以聪明的投票对我来说是最有效的。您可以添加任意多的事件类型,但这些似乎对我来说做得很好。

为TS编写,但很容易修改:

const locationChangeEventType = "MY_APP-location-change";

// called on creation and every url change
export function observeUrlChanges(cb: (loc: Location) => any) {
  assertLocationChangeObserver();
  window.addEventListener(locationChangeEventType, () => cb(window.location));
  cb(window.location);
}

function assertLocationChangeObserver() {
  const state = window as any as { MY_APP_locationWatchSetup: any };
  if (state.MY_APP_locationWatchSetup) { return; }
  state.MY_APP_locationWatchSetup = true;

  let lastHref = location.href;

  ["popstate", "click", "keydown", "keyup", "touchstart", "touchend"].forEach((eventType) => {
    window.addEventListener(eventType, () => {
      requestAnimationFrame(() => {
        const currentHref = location.href;
        if (currentHref !== lastHref) {
          lastHref = currentHref;
          window.dispatchEvent(new Event(locationChangeEventType));
        }
      })
    })
  });
}

使用

observeUrlChanges((loc) => {
  console.log(loc.href)
})

其他回答

用jquery(和一个插件)就可以做到

$(window).bind('hashchange', function() {
 /* things */
});

http://benalman.com/projects/jquery-hashchange-plugin/

否则,你必须使用setInterval并检查哈希事件的变化(window.location.hash)

更新!一个简单的草稿

function hashHandler(){
    this.oldHash = window.location.hash;
    this.Check;

    var that = this;
    var detect = function(){
        if(that.oldHash!=window.location.hash){
            alert("HASH CHANGED - new has" + window.location.hash);
            that.oldHash = window.location.hash;
        }
    };
    this.Check = setInterval(function(){ detect() }, 100);
}

var hashDetection = new hashHandler();

在现代浏览器(IE8+, FF3.6+, Chrome)中,你可以只听窗口上的hashchange事件。

在一些旧的浏览器中,您需要一个计时器来持续检查location.hash。如果你正在使用jQuery,有一个插件可以做到这一点。

例子

下面我将撤销所有URL更改,以保持滚动:

<script type="text/javascript">
  if (window.history) {
    var myOldUrl = window.location.href;
    window.addEventListener('hashchange', function(){
      window.history.pushState({}, null, myOldUrl);
    });
  }
</script>

请注意,以上使用的历史api可用于Chrome, Safari, Firefox 4+和Internet Explorer 10pp4+

我希望能够添加locationchange事件监听器。经过下面的修改,我们就可以这样做了

window.addEventListener('locationchange', function () {
    console.log('location changed!');
});

相比之下,window.addEventListener('hashchange',() =>{})只会在url中标签后的部分发生变化时触发,而window.addEventListener('popstate',() =>{})并不总是工作。

这种修改类似于Christian的回答,修改了history对象以添加一些功能。

默认情况下,在这些修改之前,有一个popstate事件,但是没有pushstate和replacestate事件。

这将修改这三个函数,以便所有函数都触发一个自定义locationchange事件供您使用,如果您想使用这些事件,还可以推送state和replacestate事件。

这些是修改:

(() => {
    let oldPushState = history.pushState;
    history.pushState = function pushState() {
        let ret = oldPushState.apply(this, arguments);
        window.dispatchEvent(new Event('pushstate'));
        window.dispatchEvent(new Event('locationchange'));
        return ret;
    };

    let oldReplaceState = history.replaceState;
    history.replaceState = function replaceState() {
        let ret = oldReplaceState.apply(this, arguments);
        window.dispatchEvent(new Event('replacestate'));
        window.dispatchEvent(new Event('locationchange'));
        return ret;
    };

    window.addEventListener('popstate', () => {
        window.dispatchEvent(new Event('locationchange'));
    });
})();

注意,我们正在创建一个闭包,将旧函数保存为新函数的一部分,以便在调用新函数时调用它。

享受吧!

var previousUrl = '';
var observer = new MutationObserver(function(mutations) {
  if (location.href !== previousUrl) {
      previousUrl = location.href;
      console.log(`URL changed to ${location.href}`);
    }
});

当点击链接将你重定向到同一域名的不同页面时,这些似乎都不起作用。因此,我提出了自己的解决方案:

let pathname = location.pathname;
window.addEventListener("click", function() {
    if (location.pathname != pathname) {
        pathname = location.pathname;
        // code
    }
});

编辑:您还可以检查popstate事件(如果用户返回一个页面)

window.addEventListener("popstate", function() {
    // code
});

最好的祝愿,

微积分