如何检测用户是不是使用后退按钮进入页面?

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 &amp;&amp; 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 刷新?

当客户端通过点击后退按钮进入页面时,如何使其加载新副本而不是缓存副本?

如何使用浏览器后退按钮关闭引导模式而不是返回页面?`

使用流路由器检测是否通过浏览器后退按钮输入了路由

如何使用 JavaScript 禁用浏览器中的后退按钮 [重复]