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

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


当前回答

在现代浏览器(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+

其他回答

看看jQuery的卸载函数。它能处理所有的事情。

https://api.jquery.com/unload/

当用户导航离开页面时,卸载事件被发送到窗口元素。这可能意味着许多事情之一。用户可以点击一个链接离开页面,或者在地址栏中输入一个新的URL。前进和后退按钮将触发事件。关闭浏览器窗口将触发该事件。即使是重新加载页面也会首先创建卸载事件。

$(window).unload(
    function(event) {
        alert("navigating");
    }
);

在做一点chrome扩展时,我遇到了一个额外的问题:有时,页面变化而不是URL。

例如,只要进入Facebook主页,然后点击“主页”按钮。你将重新加载页面,但URL不会改变(单页应用程序样式)。

99%的时间里,我们在开发网站,这样我们就可以从Angular、React、Vue等框架中获取这些事件。

但是,在我的Chrome扩展(在香草JS)的情况下,我不得不听一个事件,将触发每个“页面变化”,这通常可以通过URL变化捕获,但有时它不会。

我自己的解决方案如下:

listen(window.history.length);
var oldLength = -1;
function listen(currentLength) {
  if (currentLength != oldLength) {
    // Do your stuff here
  }

  oldLength = window.history.length;
  setTimeout(function () {
    listen(window.history.length);
  }, 1000);
}

leoneckert解决方案,应用于窗口历史记录,当单页应用中的页面改变时,窗口历史记录也会改变。

这不是火箭科学,而是我发现的最干净的解决方案,考虑到我们在这里只检查一个整数相等,而不是更大的对象或整个DOM。

享受吧!

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

如果没有窗口事件为您工作(在我的例子中不是这样),您还可以使用MutationObserver来查看根元素(非递归地)。

// capture the location at page load
let currentLocation = document.location.href;

const observer = new MutationObserver((mutationList) => {
  if (currentLocation !== document.location.href) {
    // location changed!
    currentLocation = document.location.href;

    // (do your event logic here)
  }
});

observer.observe(
  document.getElementById('root'),
  {
    childList: true,

    // important for performance
    subtree: false
  });

这可能并不总是可行的,但通常情况下,如果URL更改,根元素的内容也会更改。

我没有进行概要分析,但从理论上讲,这比计时器的开销要小,因为Observer模式通常是实现的,因此当发生更改时,它只是通过订阅进行循环。我们在这里只添加了一个订阅。另一方面,计时器必须非常频繁地检查,以确保在URL更改后立即触发事件。

此外,这比计时器更可靠,因为它消除了计时问题。

这个解决方案对我很有效:

function checkURLchange(){
    if(window.location.href != oldURL){
        alert("url changed!");
        oldURL = window.location.href;
    }
}

var oldURL = window.location.href;
setInterval(checkURLchange, 1000);