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

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


当前回答

在做一点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。

其他回答

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

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

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

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

享受吧!

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

另一种简单的方法是通过添加一个单击事件,通过类名到页面上的锚标记来检测它何时被单击,然后您现在可以使用window.location.href来获取url数据,您可以使用这些数据来向服务器运行ajax请求。简单易行。

我希望能够添加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'));
    });
})();

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

我创建了这个与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)
})