How do I use window.history in JavaScript?
I found many questions about this on Stack Overflow, but they were all very specific to certain parts. I found this question whose answers provide some helpful links, but they don't really explain how it all works, and their examples hardly do anything. I want to know more about how it all works and I want to use vanilla JavaScript.
(Also, many of the answers on other questions are years old.)
source to share
BEGINNING OF WORK
First of all, you can remove the part window
. It just history
works fine. But before we get into how everything works together, we need to know what we can use.
Important events
window.onload
This event fires whenever your web page is loaded. There are two cases that will trigger this event:
- When your web page is moved from another web page. Note that I wrote a web page, not a website. Moving between pages on the same site will trigger this event.
- Only after refreshing the web page.
window.onpopstate
This event fires when you navigate between history states that you have set. Your browser automatically sets history states (to zero) during normal browsing, but going to / from these states will not trigger this event.
window.onunload
This event fires whenever your web page is unloaded. There are two cases that will trigger this event:
- When you navigate to another web page from your web page.
- Before refreshing the web page.
Important objects
The history interface contains five functions (described below), two read-only objects (described here) and looks a bit like a linked list . Two objects contained in each "link" of a history object:
- length - the number of history states for the current browser window. It starts at 1.
- state is a JavaScript object that can contain almost anything. The default is
null
.
You can access them by calling history.length
and history.state
respectively, although history.state
can only be used to get the current state of history.
Important functions
history.go (distance)
This function does the same as clicking the Back or Forward button in your browser, with the added functionality of letting you specify exactly how far you want to go. For example, it history.go(3)
has the same effect as pressing the forward button three times, without actually loading pages between your start and end locations. A negative value also moves you backward through your story. history.go(0)
, history.go()
and even history.go(NaN)
have the same effect as updating the page (it doesn't trigger an event popstate
). If you cannot move forward / backward to the specified value, the function will do nothing.
history.back ()
This feature has the same functionality as the back button in your browser. This is equivalent history.go(-1)
. If it cannot return, the function will do nothing.
history.forward ()
This feature has the same functionality as the forward button in your browser. This is equivalent history.go(1)
. If it cannot go ahead, the function will do nothing.
history.replaceState (state, name [, location])
This function replaces the current state of history. It takes three arguments, although the latter is optional. Arguments:
- state - This is the most important argument. The object you pass to this argument will be stored in
history.state
for later retrieval. This is a deep copy, so if you change the original object later, it won't change the saved state. You can also set this value tonull
, but if you are not going to use it, there is no point in using ithistory
at all. - title - The HTML standard assumes that the string passed to this argument can be used by the browser in the user interface, but no browser is currently doing anything with it.
- location - This argument allows you to change the URL relative to the current page. It cannot be used to change the url on another website, but it can be used to change the url on another page of your website. However, I would suggest doing this, since the page doesn't actually reload, even if the url of another page is. Using back / forward will render the changed url but not change the page and call
popstate
, notload
orunload
... Refreshing the page after changing the url will load the page indicated by the url and not the previous page. This functionality can be used to provide a link to your page in its current state, but I would recommend changing the query string rather than the full URL. If this argument is not used, the URL will not change.
history.pushState (state, name [, location])
This function works the same as history.replaceState
, except that instead of the current state, a new state is put in place of the new state. All history states that were previously accessed with forward
are discarded, and the new state becomes current.
ASSEMBLY OF PARTS
The story interface is very useful for letting your users navigate dynamically generated content from their browser without reloading the entire page, but you need to be mindful of all the possible things your users can do that can affect stories.
- The first time you go to your page
- Should your users be greeted with a menu / list, specific dynamically generated content, or perhaps some random dynamically generated content?
- Will your page render without
history
or even JavaScript?
- Use
back/forward
to return to page- If your users see the same thing they saw for the first time, or should they see the result of their visit reflected in the content? (The "Welcome Back" message may be a nice touch to some, but an unwanted distraction for others.)
- Refreshing the page
- If you get a new page, go back to the start page or reload the same page? (Your users probably won't expect the latter if the URL hasn't changed.)
- Usage
back/forward
from the updated page- Should you receive new content relative to a refreshed page or reload a previously saved state?
- Go from your page
- Do you need to save something before leaving?
- Returning to the page using a deep link
- Do you have code to recognize and handle a deep link?
Note that there is no way to delete the saved state (except in the specific case with pushState()
mentioned above). It can only be replaced with new content.
ALLOWING ALL TOGETHER
Since this is starting to get terse, let's finish it off with some code.
// This function is called when the page is first loaded, when the page is refreshed,
// and when returning to the page from another page using back/forward.
// Navigating to a different page with history.pushState and then going back
// will not trigger this event as the page is not actually reloaded.
window.onload = function() {
// You can distinguish a page load from a reload by checking performance.navigation.type.
if (window.performance && window.PerformanceNavigation) {
let type = performance.navigation.type;
if (type == PerformanceNavigation.TYPE_NAVIGATE) {
// The page was loaded.
} else if (type == PerformanceNavigation.TYPE_RELOAD) {
// The page was reloaded.
} else if (type == PerformanceNavigation.TYPE_BACK_FORWARD) {
// The page was navigated to by going back or forward,
// though *not* from a history state you have set.
}
}
// Remember that the browser automatically sets the state to null on the
// first visit, so if you check for this and find it to be null, you know
// that the user hasn't been here yet.
if (history.state == null) {
// Do stuff on first load.
} else {
// Do stuff on refresh or on returning to this page from another page
// using back/forward. You may want to make the window.onpopstate function
// below a named function, and just call that function here.
}
// You can of course have code execute in all three cases. It would go here.
// You may also wish to set the history state at this time. This could go in the
// if..else statement above if you only want to replace the state in certain
// circumstances. One reason for setting the state right away would be if the user
// navigates to your page via a deep link.
let state = ...; // There might not be much to set at this point since the page was
// just loaded, but if your page gets random content, or time-
// dependent content, you may want to save something here so it can
// be retrieved again later.
let title = ...; // Since this isn't actually used by your browser yet, you can put
// anything you want here, though I would recommend setting it to
// null or to document.title for when browsers start actually doing
// something with it.
let URL = ...; // You probably don't want to change the URL just yet since the page
// has only just been loaded, in which case you shouldn't use this
// variable. One reason you might want to change the URL is if the
// user navigated to this page with a query string in the URL. After
// reading the query string, you can remove it by setting this
// variable to: location.origin + location.pathname
history.replaceState(state, title, URL); // Since the page has just been loaded, you
// don't want to push a new state; you should
// just replace the current state.
}
// This function is called when navigating between states that you have set.
// Since the purpose of `history` is to allow dynamic content changes without
// reloading the page (ie contacting the server), the code in this function
// should be fairly simple. Just things like replacing text content and images.
window.onpopstate = function() {
// Do things with history.state here.
}
// This function is called right before the page is refreshed, and right
// before leaving the page (not counting history.replaceState). This is
// your last chance to set the page history state before leaving.
window.onunload = function() {
// Finalize the history state here.
}
Note that I have never called history.pushState
anywhere. This is because history.pushState
it shouldn't be called anywhere in these functions. It should be called by a function that actually changes the page in such a way that you want your users to be able to use the back button to cancel.
So the overall setup can work like this:
- Check
if (history.state == null)
in functionwindow.onload
.- If true, overwrite history state with new information.
- If false, use history state to restore the page.
- When the user views the page, call
history.pushState
when important events happen that should be canceled with the back button. - If / When the user uses their back button and the event fires
popstate
, use the history state you set to return the page to its previous state.- Likewise if / when the user uses their forward button.
- Use an event
unload
to complete the state of the story before the user leaves the page.
source to share