【问题标题】: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 东西。

问题是如果:

  1. 页面加载时没有描述
  2. 用户添加了描述
  3. 点击链接即可离开页面
  4. 用户点击返回按钮

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

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

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

【问题讨论】:

  • 这与您引用的问题有何不同?
  • 问题类似,但我认为环境和答案不同,我可能是错的。我对其他解决方案可能解决的问题的解释是:用户单击由 ajax 加载的页面上的选项卡,然后单击另一个选项卡,依此类推。单击后退按钮将带您返回另一个页面,而不是上一个选项卡。他们想在“页面历史”中循环浏览“ajax 历史”。至少这是我对雅虎浏览器历史管理器应该做什么的印象。我想要一些更基本的东西。
  • 接受的答案包含您的 iframe 技巧。

标签: ajax browser back-button


【解决方案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.
      }
      
      猜你喜欢
      • 2010-11-11
      • 2023-03-21
      • 2016-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多