Is There a Cross-Browser Onload Event When Clicking the Back Button

Is there a cross-browser onload event when clicking the back button?

Guys, I found that JQuery has only one effect: the page is reloaded when the back button is pressed. This has nothing to do with "ready".

How does this work? Well, JQuery adds an onunload event listener.

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

By default, it does nothing. But somehow this seems to trigger a reload in Safari, Opera and Mozilla -- no matter what the event handler contains.

[edit(Nickolay): here's why it works that way: webkit.org, developer.mozilla.org. Please read those articles (or my summary in a separate answer below) and consider whether you really need to do this and make your page load slower for your users.]

Can't believe it? Try this:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
alert('first load / reload');
window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

You will see similar results when using JQuery.

You may want to compare to this one without onunload

<body><!-- Will not reload on back button -->
<script type="text/javascript">
alert('first load / reload');
window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

How to Detect Browser Back Button event - Cross Browser

(Note: As per Sharky's feedback, I've included code to detect backspaces)

So, I've seen these questions frequently on SO, and have recently run into the issue of controlling back button functionality myself. After a few days of searching for the best solution for my application (Single-Page with Hash Navigation), I've come up with a simple, cross-browser, library-less system for detecting the back button.

Most people recommend using:

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

However, this function will also be called when a user uses on in-page element that changes the location hash. Not the best user experience when your user clicks and the page goes backwards or forwards.

To give you a general outline of my system, I'm filling up an array with previous hashes as my user moves through the interface. It looks something like this:

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

Pretty straight forward. I do this to ensure cross-browser support, as well as support for older browsers. Simply pass the new hash to the function, and it'll store it for you and then change the hash (which is then put into the browser's history).

I also utilise an in-page back button that moves the user between pages using the lasthash array. 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 will move the user back to the last hash, and remove that last hash from the array (I have no forward button right now).

So. How do I detect whether or not a user has used my in-page back button, or the browser button?

At first I looked at window.onbeforeunload, but to no avail - that is only called if the user is going to change pages. This does not happen in a single-page-application using hash navigation.

So, after some more digging, I saw recommendations for trying to set a flag variable. The issue with this in my case, is that I would try to set it, but as everything is asynchronous, it wouldn't always be set in time for the if statement in the hash change. .onMouseDown wasn't always called in click, and adding it to an onclick wouldn't ever trigger it fast enough.

This is when I started to look at the difference between document, and window. My final solution was to set the flag using document.onmouseover, and disable it using document.onmouseleave.

What happens is that while the user's mouse is inside the document area (read: the rendered page, but excluding the browser frame), my boolean is set to true. As soon as the mouse leaves the document area, the boolean flips to false.

This way, I can change my 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'll note 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 a window.onbeforeunload event.

So, in short, and for people that aren't necessarily using an in-page back button or an array to store the 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
}
}

And there you have it. a simple, three-part way to detect back button usage vs in-page elements with regards to hash navigation.

EDIT:

To ensure that the user doesn't use backspace to trigger the back event, you can also include the following (Thanks to @thetoolman on 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();
}
}
});
});

When load page with Ajax, the go back button doesn't works

You've used pushState to add an entry to the browser history, but you haven't added an event handler to determine what happens when the browser navigates back. The browser won't automatically memorise the state of the DOM for you.

Here is a simple example:

<div id="content">1</div>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>

<script>
const div = document.querySelector('div');

addEventListener('click', event => {
if (event.target.tagName.toLowerCase() !== 'button') return;
const last = div.textContent;
const next = event.target.textContent;
div.textContent = next;
history.pushState({ value: next }, `Page ${next}`, `/page/${next}`);
});

addEventListener('popstate', event => {
let state = event.state;
if (state === null) {
// special case: This is the state before pushState was called
// We know what that should be:
state = { value: 1 };
}
div.textContent = state.value;
console.log('location: ' + document.location + ', state: ' + JSON.stringify(event.state));
});
</script>


Related Topics



Leave a reply



Submit