101

这个问题类似于Track when user hits back button on the browser,但不一样...我有一个解决方案,并在此处发布以供参考和反馈。如果有人有更好的选择,我会全力以赴!

情况是我有一个带有“就地编辑”的页面,例如 flickr。即有一个“单击此处添加描述”DIV,当单击它变成一个带有保存和取消按钮的文本区域。单击 Save 将数据发布到服务器以更新数据库并将新描述放入 DIV 中以代替 TEXTAREA。如果页面被刷新,新的描述会从数据库中显示,并带有“点击编辑”选项。这些天相当标准的 web 2.0 东西。

问题是,如果:

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

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

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

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

4

11 回答 11

80

使用隐藏表格。当您重新加载或点击后退按钮返回页面时,表单数据(通常)保存在浏览器中。以下内容进入您的页面(可能靠近底部):

<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 秒)。

于 2011-04-12T22:58:59.807 回答
64

这是解决这个老问题的一个非常简单的现代解决方案。

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。

于 2017-08-24T09:31:39.287 回答
13

这篇文章解释了它。请参阅下面的代码: 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>
于 2011-06-15T22:05:18.983 回答
7

您可以使用onbeforeunload事件解决它:

window.onbeforeunload = function () { }

拥有一个onbeforeunload空事件管理器功能意味着页面将在每次访问时重新构建。Javascript 将重新运行,服务器端脚本将重新运行,页面将像用户第一次点击一样构建,即使用户只是通过点击后退或前进按钮进入页面.

以下是示例的完整代码:

<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

于 2015-06-04T04:05:30.663 回答
6

对于现代浏览器,现在这似乎是正确的方法:

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

于 2020-01-08T07:28:15.830 回答
2

如上所述,我找到了一个解决方案,并在此处发布以供参考和反馈。

解决方案的第一阶段是在页面中添加以下内容:

<!-- 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>

从我在这个阶段的(最小)测试来看,这似乎可以按预期工作。我有没有忽略什么?

于 2009-05-06T11:07:04.913 回答
2

这是一个 jQuery 版本。由于 Safari 桌面/移动设备在用户按下后退按钮时处理缓存的方式,我遇到了几次需要使用它的情况。

$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        // Loading from cache
    }
});
于 2017-03-31T14:20:30.127 回答
2

您可以使用 localStorage 或 sessionStorage ( http://www.w3schools.com/html/html5_webstorage.asp ) 设置标志(而不是使用隐藏表单)。

于 2016-06-02T14:29:03.063 回答
1

使用这个页面,特别是结合@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();
    }
});
于 2016-02-26T04:20:01.577 回答
0

我今天遇到了类似的问题,我用 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 了。

于 2016-06-08T15:29:17.773 回答
0

在其他人的评论中发现了这一点(感谢 Mladen)——似乎在 Chrome 88 中运行良好。

if(String(window.performance.getEntriesByType("navigation")[0].type) === "back_forward"){
// Actions here, such as refresh page, etc.
}
于 2021-02-05T19:38:09.943 回答