2010-08-19 15 views
27

Piszę skrypt Greasemonkey dla witryny, która w pewnym momencie modyfikuje location.href.Zdarzenie, gdy window.location.href zmienia

Jak mogę uzyskać zdarzenie (za pośrednictwem window.addEventListener lub coś podobnego) po zmianie na stronie na window.location.href? Potrzebuję również dostępu do DOM dokumentu wskazującego na nowy/zmodyfikowany URL.

Widziałem inne rozwiązania, które wiążą się z przekroczeniem limitu czasu i odpytywaniem, ale chciałbym tego uniknąć, jeśli to możliwe.

Odpowiedz

31

popstate event:

popstate zdarzenie jest zwolniony, gdy aktywne zmiany pozycji historii. [...] Impreza popstate jest wyzwalany tylko wykonując działania przeglądarki, takie jak kliknięcie na przycisk back (lub dzwoniąc history.back() w JavaScript)

Tak, słuchanie popstate imprezy i wysyłanie popstate wydarzenie podczas korzystania history.pushState() powinny być wystarczające do podjęcia działań na href zmiany:

window.addEventListener('popstate', listener); 

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

Ale czy popstate będzie strzelać przed załadowaniem zawartości? – user2782001

14

Nie można uniknąć odpytywania, nie ma żadnego zdarzenia do zmiany href.

Używanie interwałów jest bardzo lekkie, jeśli nie stracisz przytomności. Sprawdzanie href co 50ms nie będzie miało znaczącego wpływu na wydajność, jeśli się o to martwisz.

+10

Jezu, że nie jest dobre –

+1

@AlexanderMills: na szczęście istnieją nowe rozwiązania 'popstate' i' hashchange'. –

6

Czy próbowałeś już przed pobraniem? To zdarzenie jest wywoływane bezpośrednio, zanim strona odpowie na żądanie nawigacji, a to powinno obejmować modyfikację 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> 

Strzeż się jednak, że to wydarzenie będzie ogień ilekroć nawigować od strony, czy to ze względu na scenariusz, lub ktoś klikając na link. Twoje prawdziwe wyzwanie, wykrywa różne przyczyny wystrzelonego wydarzenia. (Jeśli jest to ważne dla logiki)

+0

Nie jestem pewien, czy to zadziała, ponieważ często zmiany hash nie wymagają przeładowania strony. – samandmoore

+0

Potrzebuję również dostępu do nowego DOM, zaktualizowałem to pytanie, aby to wyjaśnić. –

+0

OK - nie brałem pod uwagę sytuacji "hash" - pomyślę o tym. Jeśli chodzi o możliwość uzyskania dostępu do nowego DOM, to masz pecha (jeśli chodzi o dostęp do tego z obsługi zdarzenia), ponieważ zdarzenie uruchomi się przed załadowaniem nowego DOM. Możesz być w stanie włączyć logikę do zdarzenia onload nowej strony, ale możesz mieć te same problemy w odniesieniu do stwierdzenia, czy musisz wykonać logikę dla każdego obciążenia tej strony. Czy możesz podać więcej szczegółów o tym, co próbujesz osiągnąć, w tym przepływ strony? – belugabob

2

jest domyślnym onhashchange wydarzenie, które można użyć.

Documented HERE

i mogą być używane tak:

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

window.onhashchange = locationHashChanged; 

Jeśli przeglądarka nie obsługuje oldURL i newURL można powiązać go tak:

//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

Używam tego skrypt w moim rozszerzeniu "Grab Any Media" i działa dobrze (jak youtube case)

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

}; 
Powiązane problemy