如何在JavaScript中检查URL是否已更改?例如,像GitHub这样使用AJAX的网站会在#符号后附加页面信息以创建唯一的URL而无需重新加载页面。检测URL更改的最佳方法是什么?
- 是否再次调用
onload
事件? - 是否有URL的事件处理程序?
- 还是必须每秒检查一次URL以检测更改?
如何在JavaScript中检查URL是否已更改?例如,像GitHub这样使用AJAX的网站会在#符号后附加页面信息以创建唯一的URL而无需重新加载页面。检测URL更改的最佳方法是什么?
onload
事件?我希望能够添加locationchange
事件监听器。在下面的修改后,我们就可以这样做了。
window.addEventListener('locationchange', function () {
console.log('location changed!');
});
相比之下,window.addEventListener('hashchange',() => {})
只有在 URL 中井号后的部分更改时才会触发,而 window.addEventListener('popstate',() => {})
则不总是有效。popstate
事件,但没有 pushstate
和 replacestate
事件。locationchange
事件,如果您想使用这些事件,则还包括 pushstate
和 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'));
});
})();
请注意,我们正在创建一个闭包,将旧函数保存为新函数的一部分,以便在调用新函数时随之调用旧函数。
在现代浏览器(IE8+,FF3.6+,Chrome)中,您可以在window
上侦听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>
请注意,上述使用的
history
-API可在Chrome、Safari、Firefox 4+和Internet Explorer 10pp4+中使用。
window.onhashchange = function() {
//code
}
window.onpopstate = function() {
//code
}
或者window.addEventListener('hashchange', function() {
//code
});
window.addEventListener('popstate', function() {
//code
});
使用jQuery
$(window).bind('hashchange', function() {
//code
});
$(window).bind('popstate', function() {
//code
});
在进行一些研究后编辑:
某种程度上看起来我被 Mozilla 文档上的说明所欺骗了。当代码中调用 pushState()
或 replaceState()
时,popstate
事件(及其回调函数 onpopstate
)并不会触发(参见此处)。因此,原回答并不适用于所有情况。
然而,有一种方法可以通过@alpha123 的函数猴子补丁绕过这个问题:
var pushState = history.pushState;
history.pushState = function () {
pushState.apply(history, arguments);
fireEvents('pushState', arguments); // Some event-handling function
};
翻译后的回答
考虑到这个问题的标题是"如何检测URL更改",如果您想知道完整路径何时改变(而不仅仅是哈希锚点),则可以监听popstate
事件:
window.onpopstate = function(event) {
console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
Mozilla 开发者文档中有 popstate 的参考资料
目前(2017年1月)全球92%的浏览器支持 popstate。
使用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();
window.addEventListener("hashchange", hashChanged);
- Rondetect()
函数时过于繁忙吗? - Hasib Mahmud添加一个哈希变化事件监听器!
window.addEventListener('hashchange', function(e){console.log('hash changed')});
或者,监听所有URL更改:
window.addEventListener('popstate', function(e){console.log('url changed')});
这比下面的代码好,因为只能在window.onhashchange中存在一件事情,否则你可能会覆盖其他人的代码。
// Bad code example
window.onhashchange = function() {
// Code that overwrites whatever was previously in window.onhashchange
}
这个解决方案对我有效:
function checkURLchange(){
if(window.location.href != oldURL){
alert("url changed!");
oldURL = window.location.href;
}
}
var oldURL = window.location.href;
setInterval(checkURLchange, 1000);
setInterval
更改为setTimeout
:“使用setInterval()
会在一段时间后使浏览器停止,因为它会每秒创建一个新的对checkURLchange()
的调用。 setTimeout()
是正确的解决方案,因为它仅被调用一次。” - divibisansetTimeout
换成将setInterval
移到函数之外。checkURLchange();
也变成了可选的。 - aristidesfl适用于Chrome 102+(2022-05-24)
navigation.addEventListener("navigate", e => {
console.log(`navigate ->`,e.destination.url)
});
API references WICG/navigation-api
当单击链接并重定向到同一域上的不同页面时,这些解决方案似乎都无效。因此,我自己创造了解决方案:
let pathname = location.pathname;
window.addEventListener("click", function() {
if (location.pathname != pathname) {
pathname = location.pathname;
// code
}
});
编辑:您还可以检查popstate事件(如果用户返回页面)
window.addEventListener("popstate", function() {
// code
});
祝一切顺利,
微积分
// 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更改后触发。
此外,这种方法的可靠性比定时器更高,因为它消除了时间问题。