javascript - Hendelse når window.location.href endres
Jeg skriver et Greasemonkey-skript for et nettsted som på et tidspunkt endrer location.href.
Hvordan kan jeg få en hendelse (via window.addEventListener eller noe lignende) når window.location.href endres på en side? Jeg trenger også tilgang til DOMen til dokumentet som peker til den nye/endrede URL-en.
Jeg har sett andre løsninger som involverer tidsavbrudd og polling, men jeg vil gjerne unngå det hvis mulig.
Svar #1
Jeg bruker dette skriptet i utvidelsen min «Grab Any Media» og det fungerer fint ( som i YouTube-tilfellet )
var oldHref = document.location.href;
window.onload = function() {
var bodyList = document.querySelector('body');
var observer = new MutationObserver(function(mutations) {
if (oldHref != document.location.href) {
oldHref = document.location.href;
/* Changed ! your code here */
}
});
var config = {
childList: true,
subtree: true
};
observer.observe(bodyList, config);
};
Med den nyeste JavaScript-spesifikasjonen
const observeUrlChange = () => {
let oldHref = document.location.href;
const body = document.querySelector('body');
const observer = new MutationObserver(mutations => {
if (oldHref !== document.location.href) {
oldHref = document.location.href;
/* Changed ! your code here */
}
});
observer.observe(body, { childList: true, subtree: true });
};
window.onload = observeUrlChange;
Svar #2
popstate-hendelse:
Popstate-hendelsen utløses når den aktive historikkeoppføringen endres. [...] Popstate-hendelsen utløses kun ved å utføre en nettleserhandling som å klikke på tilbake-knappen (eller ved å kalle history.back() i JavaScript)
Så, å lytte til popstate-hendelsen og sende en popstate-hendelse når man bruker history.pushState() bør være nok til å handle på href-endring:
window.addEventListener('popstate', listener);
const pushUrl = (href) => {
history.pushState({}, '', href);
window.dispatchEvent(new Event('popstate'));
};
Svar #3
I støttede nettlesere, bruk den nye Navigasjons-APIen som for øyeblikket blir implementert som en erstatning for History-APIen:
navigation.addEventListener('navigate', () => {
console.log('page changed');
});
Dette fungerer allerede i Chromium-nettlesere, men Firefox og Safari mangler det foreløpig per januar 2024.
Det forenkler problemet betydelig, og er designet spesielt med tanke på enkeltsideapplikasjoner, som er det største problemet med eksisterende løsninger. Ikke flere irriterende og dyre MutationObserver-kall!
Svar #4
Du kan ikke unngå polling, det finnes ingen hendelse for href-endring.
Å bruke intervaller er ganske lett uansett hvis du ikke overdriver. Å sjekke href hver 50. ms eller så vil ikke ha noen betydelig effekt på ytelsen hvis du er bekymret for det.
Svar #5
Det finnes en standard onhashchange-hendelse som du kan bruke.
Dokumentert HER
Og kan brukes slik:
function locationHashChanged( e ) {
console.log( location.hash );
console.log( e.oldURL, e.newURL );
if ( location.hash === "#pageX" ) {
pageX();
}
}
window.onhashchange = locationHashChanged;
Hvis nettleseren ikke støtter oldURL og newURL, kan du binde det slik:
//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;
} );
} () );
Svar #6
Gjennom Jquery, bare prøv
$(window).on('beforeunload', function () {
//your code goes here on location change
});
Ved å bruke javascript:
window.addEventListener("beforeunload", function (event) {
//your code goes here on location change
});
Se dokument: https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
Svar #7
ReactJS og andre SPA-applikasjoner bruker
history-objektet
Du kan lytte til at window.history oppdateres med følgende kode:
function watchHistoryEvents() {
const { pushState, replaceState } = window.history;
window.history.pushState = function (...args) {
pushState.apply(window.history, args);
window.dispatchEvent(new Event('pushState'));
};
window.history.replaceState = function (...args) {
replaceState.apply(window.history, args);
window.dispatchEvent(new Event('replaceState'));
};
window.addEventListener('popstate', () => console.log('popstate event'));
window.addEventListener('replaceState', () => console.log('replaceState event'));
window.addEventListener('pushState', () => console.log('pushState event'));
}
watchHistoryEvents();
