Estoy escribiendo un script de Greasemonkey para un sitio que en algún momento modifica location.href
.
¿Cómo puedo obtener un evento (vía window.addEventListener
o algo similar) cuando window.location.href
cambia en una página? También necesito acceso al DOM del documento que apunta a la URL nueva / modificada.
He visto otras soluciones que implican tiempos de espera y encuestas, pero me gustaría evitar eso si es posible.
javascript
dom
greasemonkey
dom-events
Johan Dahlin
fuente
fuente
Respuestas:
evento popstate :
Por lo tanto, escuchar el
popstate
evento y enviar unpopstate
evento cuando se usahistory.pushState()
debería ser suficiente para tomar medidas sobre elhref
cambio:window.addEventListener('popstate', listener); const pushUrl = (href) => { history.pushState({}, '', href); window.dispatchEvent(new Event('popstate')); };
fuente
pushState
Utilizo este script en mi extensión "Grab Any Media" y funciona bien ( como en el caso de 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); };
fuente
window.addEventListener("load", () => {})
embargo, usaría en lugar de window.onload :)No puede evitar el sondeo, no hay ningún evento para el cambio de href.
De todos modos, el uso de intervalos es bastante ligero si no se excede. Verificar el href cada 50 ms aproximadamente no tendrá ningún efecto significativo en el rendimiento si eso le preocupa.
fuente
popstate
yhashchange
.Hay un
onhashchange
evento predeterminado que puede utilizar.Documentado AQUÍ
Y se puede usar así:
function locationHashChanged( e ) { console.log( location.hash ); console.log( e.oldURL, e.newURL ); if ( location.hash === "#pageX" ) { pageX(); } } window.onhashchange = locationHashChanged;
Si el navegador no es compatible
oldURL
ynewURL
puede vincularlo así://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; } ); } () );
fuente
¿Has probado antes de descargar? Este evento se activa inmediatamente antes de que la página responda a una solicitud de navegación, y esto debería incluir la modificación del 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>
Sin embargo, tenga en cuenta que su evento se activará cada vez que navegue fuera de la página, ya sea por el script o porque alguien hace clic en un enlace. Tu verdadero desafío, es detectar las diferentes razones por las que el evento está siendo despedido. (Si esto es importante para tu lógica)
fuente
hash
situación, pensará en eso. En cuanto a poder acceder al nuevo DOM, entonces no tiene suerte (en lo que respecta a acceder a esto desde un controlador de eventos) ya que el evento se activará antes de que se cargue el nuevo DOM. Es posible que pueda incorporar la lógica en el evento de carga de la nueva página, pero puede tener los mismos problemas con respecto a identificar si necesita llevar a cabo la lógica para cada carga de esa página. ¿Puede proporcionar más detalles sobre lo que está tratando de lograr, incluido el flujo de la página?A través de Jquery , solo intenta
$(window).on('beforeunload', function () { //your code goes here on location change });
Usando javascript :
window.addEventListener("beforeunload", function (event) { //your code goes here on location change });
Consulte el documento: https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
fuente
Bueno, hay 2 formas de cambiar el
location.href
. O puede escribirlocation.href = "y.html"
, lo que recarga la página o puede usar la API de historial que no recarga la página. Experimenté mucho con el primero recientemente.Si abre una ventana secundaria y captura la carga de la página secundaria desde la ventana principal, los diferentes navegadores se comportan de manera muy diferente. Lo único que es común, que eliminan el documento antiguo y agregan uno nuevo, por ejemplo, agregar readystatechange o cargar controladores de eventos al documento anterior no tiene ningún efecto. La mayoría de los navegadores también eliminan los controladores de eventos del objeto de la ventana, la única excepción es Firefox. En Chrome con Karma Runner y en Firefox puedes capturar el nuevo documento en el estado de carga readyState si usas
unload + next tick
. Por lo tanto, puede agregar, por ejemplo, un controlador de eventos de carga o un controlador de eventos readystatechange o simplemente registrar que el navegador está cargando una página con un nuevo URI. En Chrome con pruebas manuales (probablemente GreaseMonkey también) y en Opera, PhantomJS, IE10, IE11 no puede capturar el nuevo documento en el estado de carga. En esos navegadores, lasunload + next tick
llamadas a la devolución de llamada unos cientos de ms después de que se activa el evento de carga de la página. El retraso es típicamente de 100 a 300 ms, pero opera simetime hace un retraso de 750 ms para el siguiente tic, lo cual da miedo. Entonces, si desea un resultado consistente en todos los navegadores, haga lo que quiera después del evento de carga, pero no hay garantía de que la ubicación no se anule antes de eso.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";
Si ejecuta su script solo en Firefox, entonces puede usar una versión simplificada y capturar el documento en un estado de carga, por ejemplo, un script en la página cargada no puede navegar antes de registrar el cambio de 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";
Si estamos hablando de aplicaciones de una sola página que cambian la parte hash de la URI, o usan la API del historial, entonces puede usar
hashchange
lospopstate
eventos y de la ventana respectivamente. Esos pueden capturar incluso si se mueve en el historial hacia atrás y hacia adelante hasta que permanezca en la misma página. El documento no cambia por esos y la página realmente no se vuelve a cargar.fuente