如何检测用户是否使用后退按钮访问了某个页面?

这个问题类似于 跟踪用户何时点击浏览器上的返回按钮,但不是相同的... 我有一个解决方案,我张贴在这里参考和反馈。如果谁有更好的选择,我洗耳恭听!

现在的情况是,我有一个“就地编辑”的页面,一个 la flickr。也就是说,有一个“点击这里添加说明”DIV,当点击变成一个 TEXTAREA 与保存和取消按钮。单击 Save 将数据发送到服务器以更新数据库,并将新的描述放在 DIV 中替换 TEXTAREA。如果刷新页面,新的说明将从数据库中显示,并带有“ click to edit”选项。这些都是标准的 web 2.0东西。

问题是,如果:

  1. 页面加载时没有说明
  2. 用户添加描述
  3. 通过单击链接导航离开页面
  4. 用户点击后退按钮

然后(从浏览器的缓存中)显示的是没有包含新描述的动态修改的 DIV 的页面版本。

这是一个相当大的问题,因为用户假设他们的更新已经丢失,并且不一定理解他们需要刷新页面才能看到更改。

因此,问题是: 如何在页面加载后将其标记为正在修改,然后检测用户何时“返回”并在该情况下强制刷新?

87630 次浏览

As mentioned above, I had found a solution and am posting it here for reference and feedback.

The first stage of the solution is to add the following to the page:

<!-- at the top of the content page -->
<IFRAME id="page_is_fresh" src="fresh.html" style="display:none;"></IFRAME>
<SCRIPT style="text/javascript">
function reload_stale_page() { location.reload(); }
</SCRIPT>

The contents of fresh.html are not important, so the following should suffice:

<!-- fresh.html -->
<HTML><BODY></BODY></HTML>

When client side code updates the page, it needs to flag the modification as follows:

function trigger_reload_if_user_clicks_back_button()
{
// "dis-arm" the reload stale page function so it doesn't fire
// until the page is reloaded from the browser's cache
window.reload_stale_page = function(){};


// change the IFRAME to point to a page that will reload the
// page when it loads
document.getElementById("page_is_fresh").src = "stale.html";
}

stale.html does all the work: When it is loaded it will call the reload_stale_page function which will refresh the page if necessary. The first time it is loaded (i.e. after the modification is made, the reload_stale_page function won't do anything.)

<!-- stale.html -->
<HTML><BODY>
<SCRIPT type="text/javascript">window.parent.reload_stale_page();</SCRIPT>
</BODY></HTML>

From my (minimal) testing at this stage, this seems to work as desired. Have I overlooked anything?

Use a hidden form. Form data is preserved (typically) in browsers when you reload or hit the back button to return to a page. The following goes in your page (probably near the bottom):

<form name="ignore_me">
<input type="hidden" id="page_is_dirty" name="page_is_dirty" value="0" />
</form>

In your javascript, you will need the following:

var dirty_bit = document.getElementById('page_is_dirty');
if (dirty_bit.value == '1') window.location.reload();
function mark_page_dirty() {
dirty_bit.value = '1';
}

The js that sniffs the form has to execute after the html is fully parsed, but you could put both the form and the js inline at the top of the page (js second) if user latency is a serious concern.

This article explains it. See the code below: http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/

<html>
<head>
<script>


function pageShown(evt){
if (evt.persisted) {
alert("pageshow event handler called.  The page was just restored from the Page Cache (eg. From the Back button.");
} else {
alert("pageshow event handler called for the initial load.  This is the same as the load event.");
}
}


function pageHidden(evt){
if (evt.persisted) {
alert("pagehide event handler called.  The page was suspended and placed into the Page Cache.");
} else {
alert("pagehide event handler called for page destruction.  This is the same as the unload event.");
}
}


window.addEventListener("pageshow", pageShown, false);
window.addEventListener("pagehide", pageHidden, false);


</script>
</head>
<body>
<a href="http://www.webkit.org/">Click for WebKit</a>
</body>
</html>

You can solve it using the onbeforeunload event:

window.onbeforeunload = function () { }

Having an onbeforeunload empty event manager function means the page will be re-built every single time it is accessed. Javascripts will re-run, server-side scripts will be re-run, the page will be built as if the user was hitting it for the very first time, even if the user got to the page just by hitting the back or forward button.

Here is the full code of an example:

<html>
<head>
<title>onbeforeunload.html</title>
<script>
window.onbeforeunload = function () { }


function myfun()
{
alert("The page has been refreshed.");
}
</script>


<body onload="myfun()">


Hello World!<br>


</body>
</html>

Try it, navigate away this page and then get back using "Back" or "Forward" buttons in your browser.

It works fine in IE, FF and Chrome.

Of course you can do whatever you want inside myfun function.

More info: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript

Using this page, especially incorporating the comment by @sajith about the answer by @Nick White and this page: http://www.mrc-productivity.com/techblog/?p=1235

<form name="ignore_me" style="display:none">
<input type="text" id="reloadValue" name="reloadValue" value="" />
</form>


$(function ()
{
var date = new Date();
var time = date.getTime();


if ($("#reloadValue").val().length === 0)
{
$("#reloadValue").val(time);
}
else
{
$("#reloadValue").val("");
window.location.reload();
}
});

You can use localStorage or sessionStorage (http://www.w3schools.com/html/html5_webstorage.asp) to set a flag (instead of using a hidden form).

I've run into a similar problem today and I solved it with localStorage (here with a bit of jQuery):

$(function() {


if ($('#page1').length) {
// this code must only run on page 1


var checkSteps = function () {
if (localStorage.getItem('steps') == 'step2') {
// if we are here, we know that:
// 1. the user is on page 1
// 2. he has been on page 2
// 3. this function is running, which means the user has submitted the form
// 4. but steps == step2, which is impossible if the user has *just* submitted the form
// therefore we know that he has come back, probably using the back button of his browser
alert('oh hey, welcome back!');
} else {
setTimeout(checkSteps, 100);
}
};


$('#form').on('submit', function (e) {
e.preventDefault();
localStorage.setItem('steps', 'step1'); // if "step1", then we know the user has submitted the form
checkOrderSteps();
// ... then do what you need to submit the form and load page 2
});
}


if ($('#page2').length) {
// this code must only run on page 2
localStorage.setItem('steps', 'step2');
}


});

Si basically:

On page 1, when the user submits the form, we set a value "steps" in localStorage to indicate what step the user has taken. At the same time, we launch a function with timeout that will check if this value has been changed (e.g. 10 times/second).

On page 2, we immediately change said value.

So if the user uses the back button and the browser restores page 1 in the exact state it was when we left it, the checkSteps function is still running, and able to detect that the value in localStorage has been changed (and can take appropriate action). Once this check has filled its purpose, there's no need to continue running it, so we simply don't use setTimeout anymore.

Here's a jQuery version. I've run into needing to use it a few times due to the way Safari desktop/mobile handles the cache when a user presses the back button.

$(window).bind("pageshow", function(event) {
if (event.originalEvent.persisted) {
// Loading from cache
}
});

Here is a very easy modern solution to this old problem.

if (window.performance && window.performance.navigation.type === window.performance.navigation.TYPE_BACK_FORWARD) {
alert('Got here using the browser "Back" or "Forward" button.');
}

window.performance is currently supported by all major browsers.

For modern browsers, this seems to be the right way now:

const perfEntries = performance.getEntriesByType('navigation');
if (perfEntries.length && perfEntries[0].type === 'back_forward') {
console.log('User got here from Back or Forward button.');
}

This is still "Experimental" as of Jan 2020, but seems to be supported well.

https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming

Found this in a comment from someone else (thanks Mladen) - seems to work very well in Chrome 88.

if(String(window.performance.getEntriesByType("navigation")[0].type) === "back_forward"){
// Actions here, such as refresh page, etc.
}