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

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


当前回答

如果没有窗口事件为您工作(在我的例子中不是这样),您还可以使用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更改后立即触发事件。

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

其他回答

我创建了这个与hashchange事件非常相似的事件

// onurlchange-event.js v1.0.1
(() => {
    const hasNativeEvent = Object.keys(window).includes('onurlchange')
    if (!hasNativeEvent) {
        let oldURL = location.href
        setInterval(() => {
            const newURL = location.href
            if (oldURL === newURL) {
                return
            }
            const urlChangeEvent = new CustomEvent('urlchange', {
                detail: {
                    oldURL,
                    newURL
                }
            })
            oldURL = newURL
            dispatchEvent(urlChangeEvent)
        }, 25)
        addEventListener('urlchange', event => {
            if (typeof(onurlchange) === 'function') {
                onurlchange(event)
            }
        })
    }
})()

使用示例:

window.onurlchange = event => {
    console.log(event)
    console.log(event.detail.oldURL)
    console.log(event.detail.newURL)
}

addEventListener('urlchange', event => {
    console.log(event)
    console.log(event.detail.oldURL)
    console.log(event.detail.newURL)
})

要收听url更改,请参见以下内容:

window.onpopstate = function(event) {
  console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};

如果您打算在某些特定条件后停止/删除侦听器,请使用此样式。

window.addEventListener('popstate', function(e) {
   console.log('url changed')
});

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

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

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

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

最好的祝愿,

微积分

您在每次调用时都开始一个新的setInterval,而没有取消前一个——可能您只是想要一个setTimeout

window.addEventListener("beforeunload", function (e) {
    // do something
}, false);