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


90

此问题类似于跟踪用户在浏览器上单击后退按钮时的问题,但不相同...我有一个解决方案,并将其发布在此处以供参考和反馈。如果有人有更好的选择,我全都听!

情况是,我的页面上有一个“就地编辑”功能,例如flickr。即有一个“单击此处添加描述” DIV,单击该按钮将变为带有“保存”和“取消”按钮的TEXTAREA。单击“保存”将数据发布到服务器以更新数据库,并将新的描述放在DIV中代替TEXTAREA。如果刷新页面,则会使用“单击以编辑”选项从数据库中显示新的描述。这些天,相当标准的Web 2.0东西。

问题是,如果:

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

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

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

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


这与您引用的问题有何不同?
innaM,2009年

这个问题是相似的,但是我认为环境以及答案是不同的,我可能是错的。我对其他解决方案可能会解决的问题的解释是:用户单击ajax加载的页面上的一个选项卡,然后单击另一个选项卡,依此类推。单击“后退”按钮将带您返回其他页面,而不是上一个选项卡。他们想在“页面历史记录”内的“ ajax历史记录”之间循环。至少那是我对Yahoo Browser History Manager应该做什么的印象。我在追求一些基本的东西。
汤姆

接受的答案是您的iframe技巧。
innaM,2009年

Answers:


79

使用隐藏的形式。当您重新加载或单击“后退”按钮返回到页面时,表单数据通常会保存在浏览器中。以下内容会出现在您的页面中(可能在底部附近):

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


5
“表单数据(通常)保存在浏览器中” –您是否可以对此进行扩展?在某些浏览器中不保留吗?或在某些情况下?
汤姆(Tom)

4
实际上,让我列出所有我认为会出错的方法。(1)Opera保持页面的完整状态,并且不会重新执行js。(2)如果对缓存设置进行了调整,以强制页面从后退按钮上从服务器加载页面,则表单数据可能会丢失,对于这个问题而言,这很好。(3)手机浏览器的缓存要小得多,并且浏览器可能已经从缓存中删除了页面(对于这些目的而言这不是问题)。
尼克·怀特

10
在某些浏览器中,隐藏的标签不会保留。因此,您可以使用隐藏的文本标签而不是使用隐藏的输入标签。<input type =“ text” value =“ 0” id ='
txt'name

2
这对我来说很棒。我敢肯定它会崩溃,但是每种解决方案都可以解决这个问题。
乔伦

它无法在带有Safari浏览器的iPhone上运行,请尝试一下,当您单击后退按钮时,不会再次调用js。
woheras 2015年

52

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

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?)。
瑞安

5
window.performance.navigation.TYPE_BACK_FORWARD是一个始终等于2的常数。因此它仅用于比较。
巴森(Bassem)

Performance.navigation支持除的Andorid与Opera Mini的所有设备,但没有问题的非常好的(developer.mozilla.org/en-US/docs/Web/API/Performance/navigation
Elbaz的

1
看起来performance.navigation已弃用,建议改为使用developer.mozilla.org/en-US/docs/Web/API/…–
RubberDuckRabbit

1
Firefox v70将支持performance.navigation = 2用于后退按钮点击。直到v70,它都错误地返回1
安迪·默瑟

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>

1
这是一个很好的答案,可以在最新的Chrome 40 / Firefox 35中使用。但是IE11不支持这些事件。
Slava Abakumov,2015年

根据caniuse.com/#feat=page-transition-events的说明IE11 +中实际上支持页面转换事件。正如我们所说的那样,该功能的全球覆盖率是88%
克里斯蒂安

仅供参考,即使从后退按钮点击,Chrome 也会返回event.persisted= false。您必须window.performance.navigation为Chrome 使用或PerformanceNavigationTiming。
安迪·默瑟


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>

从我目前的(最低)测试来看,这似乎可以正常工作。我有没有忽略什么?


我不知道,但是还没有完全测试。在某些旧版浏览器中不支持getElementById,但是很容易换成jquery或其他需要的东西。
汤姆

2

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

window.onbeforeunload = function () { }

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

这是示例的完整代码:

<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中为我工作
Jakob,

2

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


它很好的解决方法,但是如果他想每次打开网站并关闭它时都想检测到该问题,该怎么办?我需要检测一下何时打开并在关闭之前返回
Elbaz

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();
    }
});

1

这是jQuery版本。由于用户按下后退按钮时Safari桌面/移动设备处理缓存的方式,我不得不使用它几次。

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

据我所知,在Chrome中似乎无法正常工作。无论我如何访问该页面,console.log只会在else语句(为测试而添加)中触发。
路加福音

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。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.