Update 2024:
With the latest advancements, major browsers now support the Navigation API, enabling us to utilize it in the following manner:
window.navigation.addEventListener("navigate", (event) => {
console.log('location changed!');
})
If you want to learn more about the Navigation API, check out the API Reference: https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API
Prior Approach (without the Navigation API):
The objective was to include locationchange
event listeners. Following the modification below, this can be achieved by adopting the indicated method:
window.addEventListener('locationchange', function () {
console.log('location changed!');
});
Comparatively,
window.addEventListener('hashchange',() => {})
would only trigger when the section after a hashtag in a URL is altered, and
window.addEventListener('popstate',() => {})
doesn't consistently function as intended.
This particular alteration, reminiscent of Christian's response, edits the history object to introduce additional functionality.
Initially, before these revisions, solely a popstate
event existed, whereas no events for pushstate
and replacestate
were present.
These adjustments ensure that all three functions emit a customized locationchange
event for your usage, as well as pushstate
and replacestate
events if required.
The modifications implemented are as follows:
(() => {
let oldPushState = history.pushState;
history.pushState = function pushState() {
let ret = oldPushState.apply(this, arguments);
window.dispatchEvent(new Event('pushstate'));
window.dispatchEvent(new Event('locationchange'));
return ret;
};
let oldReplaceState = history.replaceState;
history.replaceState = function replaceState() {
let ret = oldReplaceState.apply(this, arguments);
window.dispatchEvent(new Event('replacestate'));
window.dispatchEvent(new Event('locationchange'));
return ret;
};
window.addEventListener('popstate', () => {
window.dispatchEvent(new Event('locationchange'));
});
})();
It is important to note that we are constructing a closure in order to retain the original function within the new one, ensuring its execution whenever the new function is called.