Event when window.location.href changes
我正在为某个网站编写Greasemonkey脚本,该脚本有时会修改
当页面上的
我已经看到了其他涉及超时和轮询的解决方案,但如果可能的话,我想避免这种情况。
popstate事件:
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)
因此,在使用
1 2 3 4 5 6 | window.addEventListener('popstate', listener); const pushUrl = (href) => { history.pushState({}, '', href); window.dispatchEvent(new Event('popstate')); }; |
我在扩展程序" Grab Any Media"中使用了此脚本,并且工作正常(如youtube case)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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); }; |
您无法避免轮询,没有任何事件可更改href。
无论如何,只要不过度使用间隔,就很轻松。如果您担心的话,每隔50毫秒左右检查一次href对性能不会有任何重大影响。
您可以使用默认的
此处记录
可以这样使用:
1 2 3 4 5 6 7 8 9 | function locationHashChanged( e ) { console.log( location.hash ); console.log( e.oldURL, e.newURL ); if ( location.hash ==="#pageX" ) { pageX(); } } window.onhashchange = locationHashChanged; |
如果浏览器不支持
1 2 3 4 5 6 7 8 9 | //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; } ); } () ); |
您是否尝试过beforeUnload?
该事件在页面响应导航请求之前立即触发,并且其中应包括对href的修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <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 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"; } ); }); <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#800000" ALINK="#FF00FF" BACKGROUND="?"> <button id="theButton">Click to navigate</button> </BODY> </HTML> |
但是请注意,无论您是离开脚本还是某个人单击链接,只要您离开页面导航,就会触发您的事件。
您真正的挑战是检测引发事件的不同原因。 (如果这对您的逻辑很重要)
通过Jquery,只需尝试
1 2 3 | $(window).on('beforeunload', function () { //your code goes here on location change }); |
通过使用javascript:
1 2 3 | window.addEventListener("beforeunload", function (event) { //your code goes here on location change }); |
请参阅文档:https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
那么,有两种方法可以更改
如果打开子窗口并从父窗口捕获子页面的负载,则不同的浏览器的行为会大不相同。唯一常见的是,它们删除了旧文档并添加了一个新文档,因此,例如,将readystatechange或load事件处理程序添加到旧文档中没有任何作用。大多数浏览器也会从window对象中删除事件处理程序,唯一的例外是Firefox。如果使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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"; |
如果仅在Firefox中运行脚本,则可以使用简化版本并以加载状态捕获文档,例如,在记录URI更改之前,已加载页面上的脚本无法导航:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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"; |
如果我们正在谈论更改URI的哈希部分或使用历史记录API的单页应用程序,则可以分别使用窗口的