Piszę skrypt Greasemonkey dla witryny, która w pewnym momencie się modyfikuje location.href
.
Jak mogę uzyskać zdarzenie (przez window.addEventListener
lub coś podobnego) w przypadku window.location.href
zmian na stronie? Potrzebuję również dostępu do DOM dokumentu wskazującego na nowy / zmodyfikowany adres URL.
Widziałem inne rozwiązania, które obejmują limity czasu i sondowanie, ale chciałbym tego uniknąć, jeśli to możliwe.
javascript
dom
greasemonkey
dom-events
Johan Dahlin
źródło
źródło
Odpowiedzi:
zdarzenie popstate :
Tak więc nasłuchiwanie
popstate
zdarzenia i wysyłaniepopstate
zdarzenia podczas używaniahistory.pushState()
powinno wystarczyć do podjęcia działań w przypadkuhref
zmiany:window.addEventListener('popstate', listener); const pushUrl = (href) => { history.pushState({}, '', href); window.dispatchEvent(new Event('popstate')); };
źródło
pushState
Używam tego skryptu w moim rozszerzeniu „Grab Any Media” i działa dobrze ( jak w przypadku 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); };
źródło
window.addEventListener("load", () => {})
zamiast window.onload chociaż :)Nie możesz uniknąć sondowania, nie ma żadnego zdarzenia dla zmiany href.
Używanie interwałów jest i tak dość lekkie, jeśli nie przesadzisz. Sprawdzanie href co około 50 ms nie będzie miało znaczącego wpływu na wydajność, jeśli się o to martwisz.
źródło
popstate
ihashchange
.Istnieje domyślne
onhashchange
zdarzenie, którego możesz użyć.Udokumentowane TUTAJ
I może być używany w ten sposób:
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
inewURL
możesz to powiązać w następujący sposób://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; } ); } () );
źródło
Czy próbowałeś wcześniej usunąć? To zdarzenie jest wywoływane bezpośrednio przed odpowiedzią strony na żądanie nawigacji i powinno obejmować modyfikację atrybutu 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>
Uważaj jednak, aby zdarzenie było uruchamiane za każdym razem , gdy opuścisz stronę, czy to z powodu skryptu, czy kliknięcia linku przez kogoś. Twoim prawdziwym wyzwaniem jest wykrycie różnych przyczyn wystrzelenia zdarzenia. (Jeśli jest to ważne dla Twojej logiki)
źródło
hash
sytuacji - pomyślę o tym. Jeśli chodzi o możliwość uzyskania dostępu do nowego DOM, to nie masz szczęścia (jeśli chodzi o dostęp do niego z modułu obsługi zdarzeń), ponieważ zdarzenie zostanie uruchomione 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 określenia, czy musisz wykonywać logikę dla każdego ładowania tej strony. Czy możesz podać więcej szczegółów na temat tego, co próbujesz osiągnąć, w tym przepływu stron?Po prostu spróbuj przez Jquery
$(window).on('beforeunload', function () { //your code goes here on location change });
Używając javascript :
window.addEventListener("beforeunload", function (event) { //your code goes here on location change });
Zobacz dokument: https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
źródło
Istnieją 2 sposoby zmiany
location.href
. Możesz albo napisaćlocation.href = "y.html"
, który przeładuje stronę, albo możesz użyć API historii, które nie przeładowuje strony. Ostatnio dużo eksperymentowałem z pierwszym.Jeśli otworzysz okno podrzędne i przechwycisz ładowanie strony podrzędnej z okna nadrzędnego, różne przeglądarki zachowują się bardzo różnie. Jedyne, co jest wspólne, jest to, że usuwają stary dokument i dodają nowy, więc na przykład dodanie programów obsługi zdarzeń readystatechange lub load do starego dokumentu nie daje żadnego efektu. Większość przeglądarek usuwa również programy obsługi zdarzeń z obiektu window, jedynym wyjątkiem jest Firefox. W przeglądarce Chrome z Karma runner i Firefox możesz przechwycić nowy dokument w pliku readyState ładowania, jeśli go używasz
unload + next tick
. Możesz więc dodać na przykład procedurę obsługi zdarzeń ładowania lub procedurę obsługi zdarzeń readystatechange lub po prostu zarejestrować, że przeglądarka ładuje stronę z nowym identyfikatorem URI. W przeglądarce Chrome z testowaniem ręcznym (prawdopodobnie również GreaseMonkey) oraz w Operze, PhantomJS, IE10, IE11 nie można przechwycić nowego dokumentu w stanie ładowania. W tych przeglądarkachunload + next tick
wywołuje oddzwanianie kilkaset ms później niż następuje załadowanie strony. Opóźnienie wynosi zwykle 100 do 300 ms, ale opera simetime powoduje 750 ms opóźnienia dla następnego taktu, co jest przerażające. Więc jeśli chcesz uzyskać spójny wynik we wszystkich przeglądarkach, robisz to, co chcesz po zdarzeniu ładowania, ale nie ma gwarancji, że lokalizacja nie zostanie wcześniej zastąpiona.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";
Jeśli uruchamiasz swój skrypt tylko w przeglądarce Firefox, możesz użyć uproszczonej wersji i przechwycić dokument w stanie ładowania, więc na przykład skrypt na załadowanej stronie nie może odejść przed zarejestrowaniem zmiany 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";
Jeśli mówimy o aplikacjach jednostronicowych, które zmieniają część hash identyfikatora URI lub używają API historii, możesz użyć
hashchange
odpowiedniopopstate
zdarzeń i zdarzeń okna. Mogą one przechwytywać, nawet jeśli poruszasz się w historii wstecz i do przodu, dopóki nie pozostaniesz na tej samej stronie. Dokument się nie zmienia, a strona nie jest ponownie ładowana.źródło