Evento quando window.location.href cambia

Sto scrivendo uno script Greasemonkey per un sito che a un certo punto modifica location.href .

Come posso ottenere un evento (tramite window.addEventListener o qualcosa di simile) quando window.location.href cambia su una pagina? Ho anche bisogno di accedere al DOM del documento che punta all’URL nuovo / modificato.

Ho visto altre soluzioni che coinvolgono timeout e sondaggi, ma vorrei evitarlo se ansible.

evento popstate :

L’evento popstate viene generato quando la voce della cronologia triggers cambia. […] L’evento popstate viene triggersto solo eseguendo un’azione browser come un clic sul pulsante Indietro (o chiamando history.back () in JavaScript)

Quindi, ascoltare l’evento popstate e inviare un evento popstate quando si utilizza history.pushState() dovrebbe essere sufficiente per intervenire sulla modifica di href :

 window.addEventListener('popstate', listener); const pushUrl = (href) => { history.pushState({}, '', href); window.dispatchEvent(new Event('popstate')); }; 

Non puoi evitare il polling, non c’è nessun evento per il cambio href.

L’uso degli intervalli è comunque abbastanza leggero se non si esagera. Controllare l’href ogni 50ms circa non avrà alcun effetto significativo sulle prestazioni se sei preoccupato per questo.

Hai provato prima di scaricare? Questo evento si triggers immediatamente prima che la pagina risponda a una richiesta di navigazione e questo dovrebbe includere la modifica di href.

                Google   

Fai attenzione, tuttavia, che il tuo evento si triggers ogni volta che ti allontani dalla pagina, indipendentemente dal fatto che si tratti di script o di qualcuno che fa clic su un link. La tua vera sfida, sta rilevando le diverse ragioni per cui l’evento è stato licenziato. (Se questo è importante per la tua logica)

Uso questo script nella mia estensione “Grab Any Media” e funziona bene ( come nel caso di 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); }; 

È disponibile un evento onhashchange predefinito.

Documentato QUI

E può essere usato in questo modo:

 function locationHashChanged( e ) { console.log( location.hash ); console.log( e.oldURL, e.newURL ); if ( location.hash === "#pageX" ) { pageX(); } } window.onhashchange = locationHashChanged; 

Se il browser non supporta oldURL e newURL , puoi associarlo in questo modo:

 //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; } ); } () ); 

Attraverso Jquery , provaci

 $(window).on('beforeunload', function () { //your code goes here on location change }); 

Utilizzando 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

Bene, ci sono 2 modi per cambiare location.href . O puoi scrivere location.href = "y.html" , che ricarica la pagina o può utilizzare l’API di cronologia che non ricarica la pagina. Ho sperimentato molto recentemente il primo.

Se si apre una finestra secondaria e si acquisisce il carico della pagina secondaria dalla finestra padre, i diversi browser si comportano in modo molto diverso. L’unica cosa che è comune è che rimuovono il vecchio documento e ne aggiungono uno nuovo, così ad esempio aggiungendo readystatechange o caricando i gestori di eventi sul vecchio documento non ha alcun effetto. La maggior parte dei browser rimuove anche i gestori di eventi dall’object window, l’unica eccezione è Firefox. In Chrome con Karma runner e in Firefox è ansible acquisire il nuovo documento nel readyState di caricamento se si utilizza unload + next tick . Quindi è ansible aggiungere ad esempio un gestore di eventi di caricamento o un gestore di eventi readystatechange o semplicemente registrare che il browser sta caricando una pagina con un nuovo URI. In Chrome con test manuale (probabilmente anche GreaseMonkey) e in Opera, PhantomJS, IE10, IE11 non puoi acquisire il nuovo documento nello stato di caricamento. In quei browser lo unload + next tick richiama la richiamata poche centinaia di msec dopo l’evento di caricamento della pagina. Il ritardo è in genere compreso tra 100 e 300 msec, ma la durata dell’opera fa un ritardo di 750 msec per il tick successivo, che è spaventoso. Quindi, se vuoi ottenere un risultato coerente in tutti i browser, allora fai ciò che vuoi dopo l’evento load, ma non è garantito che la posizione non venga sovrascritta prima.

 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"; 

Se si esegue lo script solo in Firefox, è ansible utilizzare una versione semplificata e acquisire il documento in uno stato di caricamento, quindi ad esempio uno script nella pagina caricata non può spostarsi prima di registrare la modifica dell’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"; 

Se stiamo parlando di applicazioni a pagina singola che modificano la parte hash dell’URI, o utilizzano l’API di cronologia, è ansible utilizzare hashchange gli eventi hashchange e popstate della finestra. Quelli possono catturare anche se ti muovi nella storia avanti e indietro fino a rimanere sulla stessa pagina. Il documento non cambia da quelli e la pagina non è veramente ricaricata.