如何检测 JavaScript 中的哈希值后 URL 是否已更改
如何在 JavaScript 中检查 URL 是否已更改?例如,像 GitHub 这样使用 AJAX 的网站将在 # 符号后附加页面信息,以创建唯一的 URL,而无需重新加载页面。检测此 URL 是否发生变化的最佳方法是什么?
onload
事件是否再次被调用?- URL 是否有事件处理程序?
- 或者必须每秒检查一次 URL 以检测更改?
How can I check if a URL has changed in JavaScript? For example, websites like GitHub, which use AJAX, will append page information after a # symbol to create a unique URL without reloading the page. What is the best way to detect if this URL changes?
- Is the
onload
event called again? - Is there an event handler for the URL?
- Or must the URL be checked every second to detect a change?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(21)
更新 2024:
一些现代浏览器现在可能支持导航 API,可以像这样使用:
MDN 上的导航 API 文档
之前的回答(没有导航 API):
实施下面详述的修改后,自定义
locationchange< /代码>可以使用事件,像这样:
原来,在这些修改之前,只有
popstate
事件,但是没有pushstate
和replacestate
的事件代码>.通过这些修改,这些历史记录函数还将触发自定义
locationchange
事件,以及pushstate
和replacestate
事件(如果需要)。这些是修改:
此修改与 Christian 的回答类似,修改历史对象以添加一些功能。
注意:正在创建 闭包,以将旧函数保存为是新函数的一部分,这样每当新函数被调用时它就会被调用。
其他解决方案的限制说明:
使用
window.addEventListener('hashchange',() => {})
仅当网址中主题标签后面的部分时才会响应变化。window.addEventListener('popstate',() => {})
对于检测所有导航更改并不总是可靠,因为它仅在使用浏览器按钮或类似方法向后或向前导航时触发。当通过history.pushState()或history.replaceState()以编程方式更改历史记录时,它不会触发,这通常在单页面应用程序中用于更新URL而不重新加载页面。Update 2024:
Some modern browsers may now support the Navigation API, which can be used like this:
Navigation API documentation on MDN
Previous answer (Without the Navigation API):
After implementing the modifications detailed below, a custom
locationchange
event can be used, like this:Originally, before these modifications, there is only a
popstate
event, but there are no events forpushstate
, andreplacestate
.With these modifications, these history functions will also trigger a custom
locationchange
event, and alsopushstate
andreplacestate
events in case they're needed.These are the modifications:
This modification, similar to Christian's answer, modifies the history object to add some functionality.
Note: A closure is being created, to save the old function as part of the new one, so that it gets called whenever the new one is called.
Notes on limitations of other solutions:
Using
window.addEventListener('hashchange',() => {})
will only respond when the part after a hashtag in a url changes.window.addEventListener('popstate',() => {})
is not always reliable for detecting all navigation changes because it only fires when navigating back or forward with the browser's buttons or similar methods. It does not trigger when the history is changed programmatically via history.pushState() or history.replaceState(), which are commonly used in single-page applications to update the URL without reloading the page.在现代浏览器(IE8+、FF3.6+、Chrome)中,您只需监听
window
上的hashchange
事件即可。在某些旧浏览器中,您需要一个计时器来持续检查
location.hash
。如果您使用 jQuery,则有一个 插件 可以完成此操作。下面的示例
我撤消了任何 URL 更改,以仅保持滚动:
In modern browsers (IE8+, FF3.6+, Chrome), you can just listen to the
hashchange
event onwindow
.In some old browsers, you need a timer that continually checks
location.hash
. If you're using jQuery, there is a plugin that does exactly that.Example
Below I undo any URL change, to keep just the scrolling:
或
使用 jQuery
or
with jQuery
经过一番研究后编辑:
不知何故,我似乎被 Mozilla 文档上的文档愚弄了。
popstate
事件(及其回调函数onpopstate
)未触发 每当在代码中调用pushState()
或replaceState()
时。因此,最初的答案并不适用于所有情况。然而,有一种方法可以通过根据@alpha123对函数进行猴子修补来规避这个问题:
原始答案
鉴于这个问题的标题是“如何检测 URL 更改”,当您想知道完整路径何时更改(而不仅仅是哈希锚点)时,答案是您可以听听
popstate
事件:Mozilla 文档中 popstate 的参考
目前(2017 年 1 月)有 全球 92% 的浏览器支持 popstate。
EDIT after a bit of researching:
It somehow seems that I have been fooled by the documentation present on Mozilla docs. The
popstate
event (and its callback functiononpopstate
) are not triggered whenever thepushState()
orreplaceState()
are called in code. Therefore the original answer does not apply in all cases.However there is a way to circumvent this by monkey-patching the functions according to @alpha123:
Original answer
Given that the title of this question is "How to detect URL change" the answer, when you want to know when the full path changes (and not just the hash anchor), is that you can listen for the
popstate
event:Reference for popstate in Mozilla Docs
Currently (Jan 2017) there is support for popstate from 92% of browsers worldwide.
使用jquery(和插件),您可以执行
http://benalman.com/projects/jquery-hashchange-plugin /
否则,是的,您将必须使用 setInterval 并检查哈希事件 (window.location.hash) 中的更改
更新!一个简单的草稿
With jquery (and a plug-in) you can do
http://benalman.com/projects/jquery-hashchange-plugin/
Otherwise yes, you would have to use setInterval and check for a change in the hash event (window.location.hash)
Update! A simple draft
添加哈希更改事件监听器!
或者,监听所有 URL 更改:
这比下面的代码更好,因为 window.onhashchange 中只能存在一件事,并且您可能会覆盖其他人的代码。
Add a hash change event listener!
Or, to listen to all URL changes:
This is better than something like the code below because only one thing can exist in window.onhashchange and you'll possibly be overwriting someone else's code.
适用于 Chrome 102+ (2022-05-24)
for Chrome 102+ (2022-05-24)
这个解决方案对我有用:
this solution worked for me:
如果没有一个窗口事件适合您(因为它们不适用于我的情况),您还可以使用 MutationObserver 查看根元素(非递归)。
这可能并不总是可行,但通常情况下,如果 URL 更改,根元素的内容也会更改。
我还没有分析过,但理论上这比计时器的开销要少,因为通常实现观察者模式,以便在发生更改时它只是循环遍历订阅。我们在这里只添加了一项订阅。另一方面,计时器必须非常频繁地检查,以确保在 URL 更改后立即触发事件。
此外,这很可能比计时器更可靠,因为它消除了计时问题。
If none of the window events are working for you (as they aren't in my case), you can also use a MutationObserver that looks at the root element (non-recursively).
This may not always be feasible, but typically, if the URL changes, the root element's contents change as well.
I have not profiled, but theoretically this has less overhead than a timer because the Observer pattern is typically implemented so that it just loops through the subscriptions when a change occurs. We only added one subscription here. The timer on the other hand would have to check very frequently in order to ensure that the event was triggered immediately after URL change.
Also, this has a good chance of being more reliable than a timer since it eliminates timing issues.
当单击将您重定向到同一域上的不同页面的链接时,这些似乎都不起作用。因此,我制定了自己的解决方案:
您还可以检查 popstate 事件(如果用户返回页面)
更新
Navigation API 是一项实验性功能,可能与某些浏览器不兼容;请参阅浏览器兼容性。
None of these seem to work when a link is clicked that which redirects you to a different page on the same domain. Hence, I made my own solution:
You can also check for the popstate event (if a user goes back a page)
Update
The Navigation API is an experimental feature which may not be compatible with some browsers; see browser compatibility.
虽然是一个老问题,但 Location-bar 项目非常有用。
Although an old question, the Location-bar project is very useful.
要侦听 url 更改,请参见下文:
如果您打算在某些特定条件后停止/删除侦听器,请使用此样式。
To listen to url changes, see below:
Use this style if you intend to stop/remove listener after some certain condition.
下面的答案来自这里(使用旧的javascript语法(无箭头功能,支持IE 10+)):
https://stackoverflow.com/a/52809105/9168962
The answer below comes from here(with old javascript syntax(no arrow function, support IE 10+)):
https://stackoverflow.com/a/52809105/9168962
在做一些 chrome 扩展时,我遇到了同样的问题,还有一个额外的问题:有时,页面会更改,但 URL 不会更改。
例如,只需转到 Facebook 主页,然后单击“主页” ' 按钮。您将重新加载页面,但 URL 不会更改(单页应用程序样式)。
99% 的时间,我们正在开发网站,这样我们就可以从 Angular、React、Vue 等框架获取这些事件。
但是,就我的 Chrome 扩展(在 Vanilla JS 中)而言,我必须监听每个“页面更改”都会触发的事件,通常可以通过 URL 更改捕获该事件,但有时却不能。
我的自制解决方案如下:
所以基本上是 leoneckert 解决方案,应用于窗口历史记录,当单页应用程序中的页面更改时,窗口历史记录将会更改。
不是火箭科学,而是我发现的最干净的解决方案,考虑到我们在这里只检查整数相等性,而不是更大的对象或整个 DOM。
While doing a little chrome extension, I faced the same problem with an additionnal problem : Sometimes, the page change but not the URL.
For instance, just go to the Facebook Homepage, and click on the 'Home' button. You will reload the page but the URL won't change (one-page app style).
99% of the time, we are developping websites so we can get those events from Frameworks like Angular, React, Vue etc..
BUT, in my case of a Chrome extension (in Vanilla JS), I had to listen to an event that will trigger for each "page change", which can generally be caught by URL changed, but sometimes it doesn't.
My homemade solution was the following :
So basically the leoneckert solution, applied to window history, which will change when a page changes in a single page app.
Not rocket science, but cleanest solution I found, considering we are only checking an integer equality here, and not bigger objects or the whole DOM.
在单独的线程中找到了一个有效的答案:
没有一个事件永远有效,并且猴子修补pushState事件非常漂亮大多数主要 SPA 的成功或失败。
所以智能投票对我来说最有效。您可以添加任意数量的事件类型,但这些似乎对我来说非常有效。
为 TS 编写,但易于修改:
用法
Found a working answer in a separate thread:
There's no one event that will always work, and monkey patching the pushState event is pretty hit or miss for most major SPAs.
So smart polling is what's worked best for me. You can add as many event types as you like, but these seem to be doing a really good job for me.
Written for TS, but easily modifiable:
Usage
享受!
Enjoy!
我创建了这个与 hashchange 事件非常相似的事件
使用示例:
I created this event that is very similar to the hashchange event
Example of use:
这将为您提供新的网址
This will give you the new url
另一种简单的方法是添加一个点击事件,通过类名到页面上的锚标记来检测何时被单击,然后锚标记必须采用这种格式
,然后您可以使用“窗口” .location.href”来获取url数据,即(#page_name),您可以通过ajax请求发送到服务器以获取所请求页面的html数据。
然后在服务器端,您可以用您最喜欢的后端语言实现 switch 语句,以根据客户端的请求分别呈现每个页面。
简单又容易。
Another simple way you could do this is by adding a click event, through a class name to the anchor tags on the page to detect when it has been clicked,then the anchor tags must be in this format
then you could then use the "window.location.href" to get the url data that is the (#page_name) which you can send through ajax request to the server to get the html data of the requested page.
Then in the server side you could implement a switch statement in your favorite backend language to render each page respectively as requested by the client.
Simple and Easy.
看一下 jQuery 的卸载函数。它处理所有的事情。
https://api.jquery.com/unload/
Look at the jQuery unload function. It handles all the things.
https://api.jquery.com/unload/