如何检测在 JavaScript 中散列后 URL 是否已更改

IT技术 javascript ajax
2021-01-28 18:16:43

如何在 JavaScript 中检查 URL 是否已更改?例如,使用 AJAX 的 GitHub 等网站将在 # 符号后附加页面信息以创建唯一的 URL,而无需重新加载页面。检测此 URL 是否更改的最佳方法是什么?

  • onload事件是否再次被调用?
  • URL 是否有事件处理程序?
  • 或者必须每秒检查 URL 以检测更改?
6个回答

我希望能够添加locationchange事件侦听器。下面修改后,我们就可以做到了,像这样

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

相比之下,window.addEventListener('hashchange',()=>{})只有在 url 中的主题标签之后的部分发生更改时才会触发,并且window.addEventListener('popstate',()=>{})并不总是有效。

此修改类似于Christian 的回答,修改历史对象以添加一些功能。

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

这会修改这三个功能,使所有的消防自定义locationchange事件供您使用,也pushstatereplacestate活动,如果你想使用它们。

这些是修改:

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

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

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

笔记:

我们正在创建一个闭包old = (f=>function new(){f();...})(old)替换old为一个new包含先前old保存在其中的函数(此时old未运行,但将在其中运行new

这是非常有帮助的,就像一个魅力。这应该是公认的答案。
2021-03-14 18:16:43
@joshuascotton 是的有!我会尝试将其添加到这里的答案中
2021-03-16 18:16:43
@joshuacotton => 是一个箭头函数,你可以用 function(f){ return function fname(){...} } 替换 f => function fname(){...}
2021-03-31 18:16:43
太好了,我需要的 谢谢
2021-04-06 18:16:43
有没有办法在 IE 中做到这一点?因为它不支持 =>
2021-04-10 18:16:43

在现代浏览器(IE8+、FF3.6+、Chrome)中,您可以只hashchangewindow.

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

如果路径改变,而不是散列怎么办?
2021-03-13 18:16:43
@NPC 任何处理完整 URL 更改的处理程序(没有锚标记)?
2021-03-16 18:16:43
据我了解,这仅适用于更改 # 号之后的部分(因此是事件名称)?而不是针对完整的 URL 更改,正如问题的标题所暗示的那样。
2021-03-25 18:16:43
您很少需要超时事件:使用鼠标和键盘事件进行检查。
2021-04-04 18:16:43
@SuperUberDuper 如果路径因为用户启动导航/点击链接等而改变,那么您只会看到一个beforeunload事件。如果您的代码启动了 URL 更改,它最清楚。
2021-04-10 18:16:43
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
});
如果仅在 url 中有哈希值时才触发,这如何是最佳答案?
2021-03-15 18:16:43
不适用于似乎非常流行的非哈希 url 更改,例如 Slack 实现的更改
2021-03-20 18:16:43
这必须标出答案。这是一行,使用浏览器事件模型并且不依赖于无休止的资源消耗超时
2021-03-21 18:16:43
您应该使用 addEventListener 而不是直接替换 onhashchange 值,以防其他东西也想听。
2021-04-06 18:16:43

经过一番研究后编辑:

不知何故,我似乎被 Mozilla 文档中的文档所迷惑。每当在代码中调用时,不会触发popstate事件(及其回调函数onpopstate因此,原始答案并不适用于所有情况。pushState()replaceState()

但是,有一种方法可以通过根据 @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 Docs 中 popstate 的参考

目前(2017 年 1 月)全球92%的浏览器支持 popstate

请注意,这在许多情况下也不可靠。例如,当您单击不同的亚马逊产品变体(价格下方的图块)时,它不会检测到 URL 更改。
2021-03-22 18:16:43
如果不使用 location.back(),这不会检测到从 localhost/foo 到 localhost/baa 的变化
2021-03-24 18:16:43
什么论据?我将如何设置 fireEvents?
2021-04-01 18:16:43
令人难以置信的是,我们在 2018 年仍然必须诉诸此类黑客攻击。
2021-04-03 18:16:43
这适用于我的用例 - 但就像@goat 说的 - 令人难以置信的是,没有对此的本地支持......
2021-04-10 18:16:43

使用 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();
@HasibMahmud,该代码每 100 毫秒执行 1 次相等性检查。我刚刚在我的浏览器中进行了基准测试,我可以在 1 毫秒内完成 500 次相等性检查。所以该代码使用了我处理能力的 1/50000。我不会太担心。
2021-03-14 18:16:43
你可以@BergP,使用普通的 javascript 监听器: window.addEventListener("hashchange", hashChanged);
2021-04-02 18:16:43
这么短的时间间隔对应用程序有好处吗?也就是说,它不会让浏览器忙于执行detect()功能吗?
2021-04-08 18:16:43
我可以检测 (window.location) 的变化并处理它吗?(没有jquery)
2021-04-09 18:16:43