search

Home  >  Q&A  >  body text

How to detect browser back button events - cross browser

<p>How to explicitly detect if the user pressed the back button in the browser? </p> <p>How do I use the <code>#URL</code> system to force the use of an in-page back button in a single-page web application? </p> <p>Why doesn’t the browser back button trigger its own event? ? </p>
P粉141911244P粉141911244461 days ago644

reply all(2)I'll reply

  • P粉662614213

    P粉6626142132023-08-24 14:20:51

    You can try popstate event handler, for example:

    window.addEventListener('popstate', function(event) {
        // The popstate event is fired each time when the current history entry changes.
    
        var r = confirm("You pressed a Back button! Are you sure?!");
    
        if (r == true) {
            // Call Back button programmatically as per user confirmation.
            history.back();
            // Uncomment below line to redirect to the previous page instead.
            // window.location = document.referrer // Note: IE11 is not supporting this.
        } else {
            // Stay on the current page.
            history.pushState(null, null, window.location.pathname);
        }
    
        history.pushState(null, null, window.location.pathname);
    
    }, false);

    Note: For best results, you should only load this code on the specific page where you want to implement the logic to avoid any other unexpected issues.

    The popstate event is fired every time the current history entry changes (the user navigates to a new state). When the user clicks the browser's back/forward button or when history.back(), history.forward(), history.go(), This happens when the > method is called programmatically.

    event.state is an attribute of the event, equal to the historical state object.

    For jQuery syntax, wrap it (add an even listener after the document is ready):

    (function($) {
      // Above code here.
    })(jQuery);

    See also: window.onpopstate on page load


    See also Sample pages on Single Page Applications and HTML5 PushState:

    <script>
    // jQuery
    $(window).on('popstate', function (e) {
        var state = e.originalEvent.state;
        if (state !== null) {
            //load content with ajax
        }
    });
    
    // Vanilla javascript
    window.addEventListener('popstate', function (e) {
        var state = e.state;
        if (state !== null) {
            //load content with ajax
        }
    });
    </script>

    This should be compatible with Chrome 5, Firefox 4, IE 10, Safari 6, Opera 11.5 and similar versions.

    reply
    0
  • P粉949190972

    P粉9491909722023-08-24 13:12:01

    (Note: Based on Sharky's feedback, I added code to detect the backspace key)

    So, I see these questions on SO a lot, and have recently run into issues controlling the back button functionality myself. After days of searching for the best solution for my application (single page with hashed navigation), I came up with a simple, cross-browser, library-free system to detect the back button.

    Most people recommend using:

    window.onhashchange = function() {
     //blah blah blah
    }

    However, this function is also called when the user uses an in-page element that changes the position hash. This is not the best user experience when the user clicks and the page moves back or forward.

    To give you a general outline of my system, as the user moves through the interface, I will populate an array with the previous hash values. It looks like this:

    function updateHistory(curr) {
        window.location.lasthash.push(window.location.hash);
        window.location.hash = curr;
    }

    very simple. I do this to ensure cross-browser support as well as support for older browsers. Just pass the new hash value to the function and it will store it for you, then change the hash value (and then put it in the browser's history).

    I also took advantage of an in-page back button that uses a lasthash array to move the user between pages. It looks like this:

    function goBack() {
        window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
        //blah blah blah
        window.location.lasthash.pop();
    }

    So this moves the user back to the last hash and removes the last hash from the array (I don't have a forward button now).

    so. How do I detect if the user used my in-page back button or browser button?

    At first I looked at window.onbeforeunload but to no avail - it is only called when the user wants to change the page. This does not happen in a single page application using hash navigation.

    So, after some more digging, I saw the suggestion to try setting a flag variable. In my case, the problem was that I would try to set it, but since everything is asynchronous, it wouldn't always be set in time for the if statement in the hash change. .onMouseDown is not always called in click , and adding it to onclick will never trigger it quickly enough.

    That's when I started researching the difference between documents and windows. My final solution was to set the flag using document.onmouseover and disable it using document.onmouseleave.

    What happens is that when the user's mouse is within the document area (read: the rendered page, but not the browser frame), my boolean is set to true. Once the mouse leaves the document area, the boolean value flips to false.

    In this way, I can change window.onhashchange to:

    window.onhashchange = function() {
        if (window.innerDocClick) {
            window.innerDocClick = false;
        } else {
            if (window.location.hash != '#undefined') {
                goBack();
            } else {
                history.pushState("", document.title, window.location.pathname);
                location.reload();
            }
        }
    }

    You will notice the check for #undefined. This is because if there is no history available in my array it returns undefined. I use this to ask the user if they want to leave using the window.onbeforeunload event.

    So, in a nutshell, for anyone who doesn't necessarily use an in-page back button or an array to store history:

    document.onmouseover = function() {
        //User's mouse is inside the page.
        window.innerDocClick = true;
    }
    
    document.onmouseleave = function() {
        //User's mouse has left the page.
        window.innerDocClick = false;
    }
    
    window.onhashchange = function() {
        if (window.innerDocClick) {
            //Your own in-page mechanism triggered the hash change
        } else {
            //Browser back button was clicked
        }
    }

    This is what you want. A simple three-part approach to detecting back button usage versus in-page elements in terms of hash navigation.

    edit:

    To ensure that the user does not use the backspace key to trigger the back event, you can also include the following (thanks for this question):

    $(function(){
        /*
         * this swallows backspace keys on any non-input element.
         * stops backspace -> back
         */
        var rx = /INPUT|SELECT|TEXTAREA/i;
    
        $(document).bind("keydown keypress", function(e){
            if( e.which == 8 ){ // 8 == backspace
                if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                    e.preventDefault();
                }
            }
        });
    });

    reply
    0
  • Cancelreply