Javascript window.location.href 更改时的事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3522090/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Event when window.location.href changes
提问by Johan Dahlin
I'm writing a Greasemonkey script for a site which at some point modifies location.href.
我正在为一个站点编写 Greasemonkey 脚本,该脚本在某些时候会修改location.href.
How can I get an event (via window.addEventListeneror something similar) when window.location.hrefchanges on a page? I also need access to the DOM of the document pointing to the new/modified url.
window.addEventListener当window.location.href页面发生变化时,如何获得事件(通过或类似的方式)?我还需要访问指向新/修改过的 url 的文档的 DOM。
I've seen other solutions which involve timeouts and polling, but I'd like to avoid that if possible.
我已经看到其他涉及超时和轮询的解决方案,但如果可能的话,我想避免这种情况。
回答by PHF
The popstate event is fired when the active history entry changes. [...] The popstate event is only triggered by doing a browser action such as a click on the back button (or calling history.back() in JavaScript)
当活动历史记录条目更改时,会触发 popstate 事件。[...] popstate 事件仅通过执行浏览器操作触发,例如单击后退按钮(或在 JavaScript 中调用 history.back())
So, listening to popstateevent and sending a popstateevent when using history.pushState()should be enough to take action on hrefchange:
因此,在使用时监听popstate事件并发送popstate事件history.pushState()应该足以对href更改采取行动:
window.addEventListener('popstate', listener);
const pushUrl = (href) => {
history.pushState({}, '', href);
window.dispatchEvent(new Event('popstate'));
};
回答by Leonardo Ciaccio
I use this script in my extension "Grab Any Media" and work fine ( like youtube case)
我在我的扩展程序“Grab Any Media”中使用了这个脚本并且工作正常(比如youtube案例)
var oldHref = document.location.href;
window.onload = function() {
var
bodyList = document.querySelector("body")
,observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (oldHref != document.location.href) {
oldHref = document.location.href;
/* Changed ! your code here */
}
});
});
var config = {
childList: true,
subtree: true
};
observer.observe(bodyList, config);
};
回答by Tatu Ulmanen
You can't avoid polling, there isn't any event for href change.
您无法避免轮询,没有任何用于 href 更改的事件。
Using intervals is quite light anyways if you don't go overboard. Checking the href every 50ms or so will not have any significant effect on performance if you're worried about that.
无论如何,如果你不过度使用间隔是很轻的。如果您担心,每 50 毫秒左右检查一次 href 不会对性能产生任何显着影响。
回答by iSkore
There is a default onhashchangeevent that you can use.
onhashchange您可以使用
一个默认事件。
And can be used like this:
并且可以这样使用:
function locationHashChanged( e ) {
console.log( location.hash );
console.log( e.oldURL, e.newURL );
if ( location.hash === "#pageX" ) {
pageX();
}
}
window.onhashchange = locationHashChanged;
If the browser doesn't support oldURLand newURLyou can bind it like this:
如果浏览器不支持oldURL,newURL你可以这样绑定:
//let this snippet run before your hashChange event binding code
if( !window.HashChangeEvent )( function() {
let lastURL = document.URL;
window.addEventListener( "hashchange", function( event ) {
Object.defineProperty( event, "oldURL", { enumerable: true, configurable: true, value: lastURL } );
Object.defineProperty( event, "newURL", { enumerable: true, configurable: true, value: document.URL } );
lastURL = document.URL;
} );
} () );
回答by belugabob
Have you tried beforeUnload? This event fires immediately before the page responds to a navigation request, and this should include the modification of the href.
你之前试过卸载吗?此事件在页面响应导航请求之前立即触发,这应该包括对 href 的修改。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE></TITLE>
<META NAME="Generator" CONTENT="TextPad 4.6">
<META NAME="Author" CONTENT="?">
<META NAME="Keywords" CONTENT="?">
<META NAME="Description" CONTENT="?">
</HEAD>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$(window).unload(
function(event) {
alert("navigating");
}
);
$("#theButton").click(
function(event){
alert("Starting navigation");
window.location.href = "http://www.bbc.co.uk";
}
);
});
</script>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#800000" ALINK="#FF00FF" BACKGROUND="?">
<button id="theButton">Click to navigate</button>
<a href="http://www.google.co.uk"> Google</a>
</BODY>
</HTML>
Beware, however, that your event will fire wheneveryou navigate away from the page, whether this is because of the script, or somebody clicking on a link. Your real challenge, is detecting the different reasons for the event being fired. (If this is important to your logic)
但是请注意,每当您离开页面时,您的事件都会触发,无论是因为脚本,还是因为有人点击了链接。您真正的挑战是检测触发事件的不同原因。(如果这对您的逻辑很重要)
回答by Praveen Danagoudra
Through Jquery, just try
通过Jquery,试试
$(window).on('beforeunload', function () {
//your code goes here on location change
});
By using javascript:
通过使用javascript:
window.addEventListener("beforeunload", function (event) {
//your code goes here on location change
});
Refer Document : https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
参考文档:https: //developer.mozilla.org/en-US/docs/Web/Events/beforeunload
回答by inf3rno
Well there is 2 ways to change the location.href. Either you can write location.href = "y.html", which reloads the page or can use the history API which does not reload the page. I experimented with the first a lot recently.
那么有 2 种方法可以更改location.href. 您可以编写location.href = "y.html",它会重新加载页面,或者可以使用不会重新加载页面的历史 API。我最近对第一个进行了很多实验。
If you open a child window and capture the load of the child page from the parent window, then different browsers behave very differently. The only thing that is common, that they remove the old document and add a new one, so for example adding readystatechange or load event handlers to the old document does not have any effect. Most of the browsers remove the event handlers from the window object too, the only exception is Firefox. In Chrome with Karma runner and in Firefox you can capture the new document in the loading readyState if you use unload + next tick. So you can add for example a load event handler or a readystatechange event handler or just log that the browser is loading a page with a new URI. In Chrome with manual testing (probably GreaseMonkey too) and in Opera, PhantomJS, IE10, IE11 you cannot capture the new document in the loading state. In those browsers the unload + next tickcalls the callback a few hundred msecs later than the load event of the page fires. The delay is typically 100 to 300 msecs, but opera simetime makes a 750 msec delay for next tick, which is scary. So if you want a consistent result in all browsers, then you do what you want to after the load event, but there is no guarantee the location won't be overridden before that.
如果您打开一个子窗口并从父窗口捕获子页面的负载,那么不同的浏览器的行为就会大不相同。唯一的共同点是它们删除旧文档并添加一个新文档,因此例如向旧文档添加 readystatechange 或 load 事件处理程序不会产生任何影响。大多数浏览器也从 window 对象中删除了事件处理程序,唯一的例外是 Firefox。在带有 Karma runner 的 Chrome 和 Firefox 中,如果您使用,您可以在加载就绪状态中捕获新文档unload + next tick. 因此,您可以添加例如加载事件处理程序或 readystatechange 事件处理程序,或者仅记录浏览器正在加载具有新 URI 的页面。在 Chrome 手动测试(也可能是 GreaseMonkey)和 Opera、PhantomJS、IE10、IE11 中,您无法在加载状态下捕获新文档。在这些浏览器中unload + next tick,在页面加载事件触发后几百毫秒调用回调。延迟通常是 100 到 300 毫秒,但是 Opera simetime 为下一个滴答设置了 750 毫秒的延迟,这很可怕。因此,如果您希望在所有浏览器中获得一致的结果,那么您可以在加载事件之后做您想做的事情,但不能保证在此之前不会覆盖该位置。
var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");
var callBacks = [];
var uglyHax = function (){
var done = function (){
uglyHax();
callBacks.forEach(function (cb){
cb();
});
};
win.addEventListener("unload", function unloadListener(){
win.removeEventListener("unload", unloadListener); // Firefox remembers, other browsers don't
setTimeout(function (){
// IE10, IE11, Opera, PhantomJS, Chrome has a complete new document at this point
// Chrome on Karma, Firefox has a loading new document at this point
win.document.readyState; // IE10 and IE11 sometimes fails if I don't access it twice, idk. how or why
if (win.document.readyState === "complete")
done();
else
win.addEventListener("load", function (){
setTimeout(done, 0);
});
}, 0);
});
};
uglyHax();
callBacks.push(function (){
console.log("cb", win.location.href, win.document.readyState);
if (win.location.href !== "http://localhost:4444/y.html")
win.location.href = "http://localhost:4444/y.html";
else
console.log("done");
});
win.location.href = "http://localhost:4444/x.html";
If you run your script only in Firefox, then you can use a simplified version and capture the document in a loading state, so for example a script on the loaded page cannot navigate away before you log the URI change:
如果您仅在 Firefox 中运行您的脚本,那么您可以使用简化版本并在加载状态下捕获文档,例如,在您记录 URI 更改之前,加载页面上的脚本无法导航:
var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");
var callBacks = [];
win.addEventListener("unload", function unloadListener(){
setTimeout(function (){
callBacks.forEach(function (cb){
cb();
});
}, 0);
});
callBacks.push(function (){
console.log("cb", win.location.href, win.document.readyState);
// be aware that the page is in loading readyState,
// so if you rewrite the location here, the actual page will be never loaded, just the new one
if (win.location.href !== "http://localhost:4444/y.html")
win.location.href = "http://localhost:4444/y.html";
else
console.log("done");
});
win.location.href = "http://localhost:4444/x.html";
If we are talking about single page applications which change the hash part of the URI, or use the history API, then you can use the hashchangeand the popstateevents of the window respectively. Those can capture even if you move in history back and forward until you stay on the same page. The document does not changes by those and the page is not really reloaded.
如果我们谈论的是更改 URI 哈希部分的单页应用程序,或者使用历史 API,那么您可以分别使用窗口的hashchange和popstate事件。即使您在历史中前后移动,直到您停留在同一页面上,这些也可以捕获。文档不会被那些更改,页面也不会真正重新加载。

