2010-08-19 36 views
27

Estoy escribiendo un script de Greasemonkey para un sitio que en algún momento modifica location.href.Evento cuando window.location.href cambia

¿Cómo puedo obtener un evento (a través de window.addEventListener o algo similar) cuando window.location.href cambia en una página? También necesito acceder 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.

Respuesta

31

popstate event:

El evento popstate se activa cuando la entrada de la lista activa. [...] El evento popstate sólo se activa al hacer una acción navegador como un clic en el botón de retroceso (o llamando history.back() en JavaScript)

Así, escuchando popstate evento y el envío de una popstate caso cuando se utiliza history.pushState() debería ser suficiente para tomar una decisión sobre el cambio href:

window.addEventListener('popstate', listener); 

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

¿Pero se disparará el estado emergente antes de que se cargue el contenido? – user2782001

14

No puede evitar las encuestas, no hay ningún evento para el cambio de href.

El uso de intervalos es bastante ligero de todos modos si no se excede. Controlar el href cada 50 ms aproximadamente no tendrá ningún efecto significativo en el rendimiento si le preocupa eso.

+10

uff que no es bueno –

+1

@ AlexanderMills: afortunadamente existen estas nuevas soluciones de 'popstate' y' hashchange'. –

6

¿Has probado antes de descargar? Este evento se dispara inmediatamente antes de que la página responda a una solicitud de navegación, y esto debería incluir la modificación de la 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> 

cuidado, sin embargo, que su evento se dispara cada vez que que navegar fuera de la página, si esto es debido a la secuencia de comandos, o alguien al hacer clic en un enlace. Su verdadero desafío es detectar las diferentes razones por las que se desencadenó el evento. (Si esto es importante para su lógica)

+0

No estoy seguro si esto funcionará porque a menudo los cambios hash no implican una recarga de página. – samandmoore

+0

Necesito acceso al nuevo DOM también, actualicé la pregunta para aclarar eso. –

+0

OK - no consideró la situación 'hash' - pensará en eso. En cuanto a poder acceder al nuevo DOM, entonces no tiene suerte (en cuanto a acceder a esto desde un controlador de eventos) ya que el evento se activará antes de que se haya cargado 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 la identificación de si necesita llevar a cabo la lógica para cada carga de esa página. ¿Puede proporcionar más detalles sobre lo que está intentando lograr, incluido el flujo de páginas? – belugabob

2

Hay una onhashchange evento predeterminado que puede utilizar.

Documented HERE

y se puede utilizar como esto:

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 soporta oldURL y newURL que se puede unir de esta manera:

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

utilizo este script en mi extensión "Grab Any Media" y funciona bien (como 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); 

}; 
Cuestiones relacionadas