简体   繁体   中英

How to use history.pushState in conjunction with back functionality of the browser

I use history.pushState and it works like a charm, except for the problem that once the url was manipulated correctly if you hit "back" in chromium or firefox, the url changes, but the page is not reloaded.

To elaborate:

We start at mysite.tld

Now (after some user interaction) we use history.pushState and change the url to be mysite.tld/some/subpage . The page gets re-rendered accordingly.

Now if you hit "back", the url changes, but NOT the page! If you refresh, the page is refreshed.

My naive (I am an absolute javascript noob) was to add an eventListener as such:

dom.window.addEventListener("popstate",
  {
    (event: Event) =>
    {
      dom.window.location.reload()
    }
  })

But of course that has some unpleasant sideeffects (whenever the url changes, it reloads the page. Very bad for eg galleries or slideshows)

The pushstate feature allows you to reflect the state of your client application in the browser history (URL, title).

This is the flow

  • The user changes the state of the application
  • The application alters the state of the history
    • Set data that represents the state of your application (eg current data displayed)
    • Set the URL to reflect the state of your application
  • The user navigates (changes the state), which triggers a popstate event
    • The event contains a state property that is the data you've set when pushing state
    • You update the view of your application according to the state

Look at this example (commented for explaination):

popstate.html

<!DOCTYPE html>
<html>
<head>
    <title>Pushstate/Popstate</title>
</head>
<body>
    <a href="javascript: void(0)">increment</a>
    <div id="output">?</div>
    <script type="text/javascript">
        window.onload = function() {
            let identifier = 0,
                match,
                query,
                identifiererEl = document.getElementById("output");

            // - Since all URL properties can be accessed clientside, 
            //   the request data is extracted from the current URL.
            // - This can be seen like an ID that the server may use 
            //   to find the actual content
            // - Note that history.state makes no sense in this case, 
            //   since it is null when the script first runs.
            match = /identifier=(\d+)/.exec(location.search);

            // This emulates the behaviour of a server it won't make sense in 
            // a client side application
            if (match) {
                // Set the identifier with the data "from the server"
                identifier = Number(match[1]) || 0;
                // Make the view initially reflect the state
                render(identifier);
            }

            function render(text) {
                identifiererEl.textContent = text;
            }

            // Listen to user interaction to alter the data, render and 
            // push the state
            document.querySelector("a").addEventListener("click", (e) => {
                // Increment only for simplicity
                identifier++;

                render(identifier);

                history.pushState(
                    { identifier: identifier },
                    "",
                    `/popstate.html?identifier=${identifier}`
                );
            });

            // Listen to state changes to update the view
            window.addEventListener("popstate", (e) => {
                // Here you'd determine the actual data to render.
                // For simplicity the identifier itself is rendered.
                render(e.state.identifier);
            });
        };
    </script>
</body>
</html>

Speaking of the gallery example, the identifier could be the photo ID and render() could update the source of the image. Of course you're responsible for fetching all or the next/previous photos (either via AJAX or inlined into the page source).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM