如何检测用户是不是使用后退按钮进入页面?
Posted
技术标签:
【中文标题】如何检测用户是不是使用后退按钮进入页面?【英文标题】:How do I detect if a user has got to a page using the back button?如何检测用户是否使用后退按钮进入页面? 【发布时间】:2010-10-24 03:55:42 【问题描述】:这个问题与Track when user hits back button on the browser 类似,但不一样...我有一个解决方案,并在此处发布以供参考和反馈。如果有人有更好的选择,我会全力以赴!
情况是我有一个带有“就地编辑”的页面,例如 flickr。 IE。有一个“单击此处添加描述”DIV,当单击它时会变成一个带有保存和取消按钮的 TEXTAREA。单击 Save 将数据发布到服务器以更新数据库并将新描述放入 DIV 中以代替 TEXTAREA。如果页面被刷新,新的描述会从数据库中显示,并带有“点击编辑”选项。这些天相当标准的 web 2.0 东西。
问题是如果:
-
页面加载时没有描述
用户添加了描述
点击链接即可离开页面
用户点击返回按钮
然后显示(来自浏览器的缓存)的是页面的版本,没有包含新描述的动态修改的 DIV。
这是一个相当大的问题,因为用户假设他们的更新已经丢失,并且不一定明白他们需要刷新页面才能看到更改。
所以,问题是:如何在页面加载后将页面标记为正在修改,然后检测用户何时“返回”并在这种情况下强制刷新?
【问题讨论】:
这与您引用的问题有何不同? 问题类似,但我认为环境和答案不同,我可能是错的。我对其他解决方案可能解决的问题的解释是:用户单击由 ajax 加载的页面上的选项卡,然后单击另一个选项卡,依此类推。单击后退按钮将带您返回另一个页面,而不是上一个选项卡。他们想在“页面历史”中循环浏览“ajax 历史”。至少这是我对雅虎浏览器历史管理器应该做什么的印象。我想要一些更基本的东西。 接受的答案包含您的 iframe 技巧。 【参考方案1】:使用隐藏形式。当您重新加载或点击后退按钮返回页面时,表单数据(通常)保存在浏览器中。以下内容进入您的页面(可能靠近底部):
<form name="ignore_me">
<input type="hidden" id="page_is_dirty" name="page_is_dirty" value="0" />
</form>
在您的 javascript 中,您将需要以下内容:
var dirty_bit = document.getElementById('page_is_dirty');
if (dirty_bit.value == '1') window.location.reload();
function mark_page_dirty()
dirty_bit.value = '1';
嗅探表单的 js 必须在 html 完全解析后执行,但如果用户延迟是一个严重问题,您可以将表单和 js 内联放在页面顶部(js 秒)。
【讨论】:
“表单数据(通常)保存在浏览器中”——你能扩展它吗?它不是在某些浏览器中保留吗?还是在某些情况下? 实际上,让我列出所有我能想到的出错方式。 (1) Opera保持页面的完整状态,不会重新执行js。 (2) 如果您的缓存设置经过调整以强制页面从服务器上的后退按钮加载,则表单数据可能会丢失,这对于这个问题来说很好。 (3) 手机浏览器的缓存要小得多,浏览器可能已经从缓存中删除了页面(对于这些目的来说不是问题)。 在某些浏览器中隐藏标签不会被保留。所以你可以使用隐藏的文本标签而不是使用隐藏的输入标签。 这对我很有用。我敢肯定它会出现故障,但每个解决方案都可以解决这个问题。 当心,这个脚本会导致无限循环!至少在 Firefox 中。因为重新加载后,隐藏输入的值仍然等于 1。Bassem 解决方案,似乎是唯一真正有效的解决方案。【参考方案2】:这是解决这个老问题的一个非常简单的现代解决方案。
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。
【讨论】:
我没听说过这个。我刚刚找到了这个文档 (developer.mozilla.org/en-US/docs/Web/API/Performance/navigation),很想听听您详细说明(例如,为什么需要window.performance && window.performance.navigation.type
而不仅仅是 window.performance.navigation.TYPE_BACK_FORWARD
?)。
window.performance.navigation.TYPE_BACK_FORWARD
是一个常数,总是等于 2。所以它只是用来比较。
看起来performance.navigation
已被弃用,建议改用developer.mozilla.org/en-US/docs/Web/API/…
这将使您的脚本在 Safari 上崩溃 - Mac 和移动设备
Firefox v70 将支持 performance.navigation = 2
用于后退按钮点击。在 v70 之前,它错误地返回了 1
。【参考方案3】:
这篇文章解释了它。请看下面的代码: 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>
【讨论】:
这是一个很好的答案,适用于最新的 Chrome 40 / Firefox 35。不过,IE11 不支持这些事件。 根据caniuse.com/#feat=page-transition-events IE11+ 实际上支持页面转换事件正如我们所说,该功能的全球覆盖率为 88% 仅供参考,Chrome 会返回event.persisted
= false
,即使从后退按钮点击也是如此。对于 Chrome,您必须使用 window.performance.navigation
或 PerformanceNavigationTiming。【参考方案4】:
您可以使用 onbeforeunload 事件解决它:
window.onbeforeunload = function ()
拥有一个 onbeforeunload 空事件管理器功能意味着页面将在每次访问时重新构建。 Javascripts 将重新运行,服务器端脚本将重新运行,页面将像用户第一次点击一样构建,即使用户只是通过点击后退或前进按钮进入页面.
这是一个示例的完整代码:
<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>
尝试一下,离开此页面,然后使用浏览器中的“后退”或“前进”按钮返回。
在 IE、FF 和 Chrome 中运行良好。
当然,您可以在 myfun 函数中为所欲为。
更多信息: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript
【讨论】:
为我在 Safari 中工作【参考方案5】:对于现代浏览器来说,现在这似乎是正确的方式:
const perfEntries = performance.getEntriesByType('navigation');
if (perfEntries.length && perfEntries[0].type === 'back_forward')
console.log('User got here from Back or Forward button.');
截至 2020 年 1 月,这仍是“实验性”,但似乎得到了很好的支持。
https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming
【讨论】:
最好使用 === 而不是 == Safari(桌面和移动)不支持。【参考方案6】:如上所述,我找到了解决方案,并在此处发布以供参考和反馈。
解决方案的第一阶段是在页面中添加以下内容:
<!-- 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>
fresh.html
的内容并不重要,所以以下内容就足够了:
<!-- fresh.html -->
<HTML><BODY></BODY></HTML>
当客户端代码更新页面时,需要如下标记修改:
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
完成所有工作:当它被加载时,它将调用reload_stale_page
函数,该函数将在必要时刷新页面。第一次加载(即修改后,reload_stale_page
函数不会做任何事情。)
<!-- stale.html -->
<HTML><BODY>
<SCRIPT type="text/javascript">window.parent.reload_stale_page();</SCRIPT>
</BODY></HTML>
从我在这个阶段的(最小)测试来看,这似乎可以按预期工作。我忽略了什么吗?
【讨论】:
我不知道,但我还没有完全测试过。一些较旧的浏览器不支持 getElementById,但如果需要,可以很容易地换成 jquery 或其他东西。【参考方案7】:您可以使用 localStorage 或 sessionStorage (http://www.w3schools.com/html/html5_webstorage.asp) 设置标志(而不是使用隐藏表单)。
【讨论】:
它很好的解决方法,但是如果他每次都想检测到这个,当我打开网站并关闭它时,我需要检测我何时打开并在关闭前返回【参考方案8】:这是一个 jQuery 版本。由于 Safari 桌面/移动设备在用户按下后退按钮时处理缓存的方式,我曾多次需要使用它。
$(window).bind("pageshow", function(event)
if (event.originalEvent.persisted)
// Loading from cache
);
【讨论】:
据我所知,在 Chrome 中似乎不起作用。无论我如何访问该页面,console.log 只会在 else 语句中触发(添加用于测试)。【参考方案9】:使用这个页面,特别是结合@sajith 对@Nick White 的回答和这个页面的评论: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();
);
【讨论】:
【参考方案10】:我今天遇到了类似的问题,我用 localStorage 解决了它(这里用一点 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');
);
基本上是:
在第 1 页,当用户提交表单时,我们在 localStorage 中设置了一个值“steps”来指示用户采取了哪一步。同时,我们启动了一个带超时功能的函数,它会检查这个值是否已经改变(例如 10 次/秒)。
在第 2 页,我们立即更改所述值。
因此,如果用户使用后退按钮并且浏览器将第 1 页恢复到我们离开时的确切状态,则 checkSteps 函数仍在运行,并且能够检测到 localStorage 中的值已更改(并且可以采取适当的行动)。一旦这个检查完成了它的目的,就没有必要继续运行它了,所以我们干脆不再使用 setTimeout。
【讨论】:
【参考方案11】:在其他人的评论中发现了这一点(感谢 Mladen)——似乎在 Chrome 88 中运行良好。
if(String(window.performance.getEntriesByType("navigation")[0].type) === "back_forward")
// Actions here, such as refresh page, etc.
【讨论】:
已弃用。 developer.mozilla.org/en-US/docs/Web/API/Performance/navigation以上是关于如何检测用户是不是使用后退按钮进入页面?的主要内容,如果未能解决你的问题,请参考以下文章
React Router v4 - 如何检测后退按钮导航与 url 刷新?