Wie erkenne ich mithilfe der Schaltfläche "Zurück", ob ein Benutzer zu einer Seite gelangt ist?


90

Diese Frage ähnelt dem Verfolgen, wenn der Benutzer im Browser auf die Schaltfläche "Zurück" klickt , ist jedoch nicht dieselbe ... Ich habe eine Lösung und poste sie hier als Referenz und Feedback. Wenn jemand bessere Möglichkeiten hat, bin ich ganz Ohr!

Die Situation ist, dass ich eine Seite mit einem "In-Place-Edit" habe, a la flickr. Dh es gibt einen DIV "Klicken Sie hier, um eine Beschreibung hinzuzufügen", der sich beim Klicken in eine TEXTAREA mit den Schaltflächen Speichern und Abbrechen verwandelt. Wenn Sie auf Speichern klicken, werden die Daten an den Server gesendet, um die Datenbank zu aktualisieren, und die neue Beschreibung wird anstelle von TEXTAREA in die DIV eingefügt. Wenn die Seite aktualisiert wird, wird die neue Beschreibung aus der Datenbank mit der Option "Klicken zum Bearbeiten" angezeigt. Ziemlich normales Web 2.0-Zeug in diesen Tagen.

Das Problem ist, dass wenn:

  1. Die Seite wird ohne Beschreibung geladen
  2. Eine Beschreibung wird vom Benutzer hinzugefügt
  3. Die Seite wird durch Klicken auf einen Link entfernt
  4. Der Benutzer klickt auf die Schaltfläche Zurück

Anschließend wird (aus dem Cache des Browsers) die Version der Seite ohne den dynamisch geänderten DIV angezeigt, der die neue Beschreibung enthält.

Dies ist ein ziemlich großes Problem, da der Benutzer davon ausgeht, dass sein Update verloren gegangen ist und nicht unbedingt versteht, dass er die Seite aktualisieren muss, um die Änderungen zu sehen.

Die Frage lautet also: Wie können Sie eine Seite nach dem Laden als geändert markieren und dann erkennen, wann der Benutzer "dorthin zurückkehrt" und in dieser Situation eine Aktualisierung erzwingen?


Wie unterscheidet sich das von der von Ihnen zitierten Frage?
InnaM

Die Frage ist ähnlich, aber ich denke, die Umgebung und daher die Antwort ist anders, ich könnte mich irren. Meine Interpretation dessen, was ein Problem sein könnte, das mit der anderen Lösung gelöst werden könnte, lautet: Der Benutzer klickt auf eine Registerkarte auf einer Seite, die von Ajax geladen wird, dann auf eine andere Registerkarte und so weiter. Wenn Sie auf die Schaltfläche "Zurück" klicken, kehren Sie zu einer anderen Seite zurück, nicht zur vorherigen Registerkarte. Sie möchten den "Ajax-Verlauf" innerhalb des "Seitenverlaufs" durchlaufen. Zumindest ist das mein Eindruck davon, was der Yahoo Browser History Manager tun soll. Ich war auf der Suche nach etwas Grundlegenderem.
Tom

Die akzeptierte Antwort enthält Ihren Iframe-Trick.
InnaM

Antworten:


79

Verwenden Sie ein verstecktes Formular. Formulardaten bleiben (normalerweise) in Browsern erhalten, wenn Sie neu laden oder auf die Schaltfläche "Zurück" klicken, um zu einer Seite zurückzukehren. Folgendes wird auf Ihrer Seite angezeigt (wahrscheinlich ganz unten):

<form name="ignore_me">
    <input type="hidden" id="page_is_dirty" name="page_is_dirty" value="0" />
</form>

In Ihrem Javascript benötigen Sie Folgendes:

var dirty_bit = document.getElementById('page_is_dirty');
if (dirty_bit.value == '1') window.location.reload();
function mark_page_dirty() {
    dirty_bit.value = '1';
}

Das js, das das Formular abruft, muss ausgeführt werden, nachdem das HTML vollständig analysiert wurde. Sie können jedoch sowohl das Formular als auch das js oben auf der Seite inline setzen (js Sekunde), wenn die Benutzerlatenz ein ernstes Problem darstellt.


5
"Formulardaten bleiben (normalerweise) in Browsern erhalten" - können Sie das erweitern? Wird es in einigen Browsern nicht beibehalten? oder in einigen Situationen?
Tom

4
Lassen Sie mich alle Möglichkeiten auflisten, wie ich mir vorstellen kann, dass etwas schief geht. (1) Opera behält den vollständigen Status der Seite bei und führt das js nicht erneut aus. (2) Wenn Ihre Cache-Einstellungen so angepasst werden, dass die Seite auf der Zurück-Schaltfläche vom Server geladen wird, gehen möglicherweise die Formulardaten verloren, was für die Zwecke dieser Frage in Ordnung ist. (3) Telefonbrowser haben einen viel kleineren Cache und der Browser hat die Seite möglicherweise bereits aus dem Cache entfernt (für diese Zwecke kein Problem).
Nick White

10
In einigen Browsern bleiben versteckte Tags nicht erhalten. Sie können also ein verstecktes Text-Tag anstelle eines versteckten Eingabe-Tags verwenden. <input type = "text" value = "0" id = 'txt' name = 'txt' style = "display: none" />
Sajith

2
Das hat bei mir super funktioniert. Ich bin sicher, es gibt Situationen, in denen es zusammenbricht, aber jede Lösung wird für dieses Problem.
Joren

Es funktioniert nicht auf dem iPhone mit Safari-Browser. Versuchen Sie es. Wenn Sie auf die Schaltfläche "Zurück" klicken, wird js nicht erneut aufgerufen.
Phänomene

51

Hier ist eine sehr einfache moderne Lösung für dieses alte Problem.

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 wird derzeit von allen gängigen Browsern unterstützt.


Ich hatte noch nichts davon gehört. Ich habe gerade diese Dokumentation gefunden ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation ) und wäre interessiert, Sie ausführlich zu hören (z. B. warum die Notwendigkeit window.performance && window.performance.navigation.typestatt nur window.performance.navigation.TYPE_BACK_FORWARD?).
Ryan

5
window.performance.navigation.TYPE_BACK_FORWARDist eine Konstante, die immer gleich 2 ist. Sie wird also nur zum Vergleich verwendet.
Bassem

Performance.navigation wird auf allen Geräten außer andorid & opera mini unterstützt, aber kein Problem, es ist sehr schön ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation )
Elbaz

1
Sieht aus wie performance.navigationveraltet und es wird empfohlen, stattdessen developer.mozilla.org/en-US/docs/Web/API/… zu verwenden
RubberDuckRabbit

1
Firefox v70 unterstützt performance.navigation = 2für Treffer auf der Zurück-Schaltfläche. Bis v70 wurde es falsch zurückgegeben 1.
Andy Mercer

13

Dieser Artikel erklärt es. Siehe den folgenden Code: 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
Dies ist eine gute Antwort und funktioniert in Chrome 40 / Firefox 35. IE11 unterstützt diese Ereignisse jedoch nicht.
Slava Abakumov

Laut caniuse.com/#feat=page-transition-events werden Seitenübergangsereignisse tatsächlich in IE11 + unterstützt. Während wir sprechen, gibt es 88% globale Abdeckung der Funktion
Cristian

Zu Ihrer Information, Chrome gibt event.persisted= zurück false, auch wenn Sie auf die Schaltfläche "Zurück" klicken. Sie müssen window.performance.navigationoder PerformanceNavigationTiming für Chrome verwenden.
Andy Mercer


2

Wie oben erwähnt, hatte ich eine Lösung gefunden und poste sie hier als Referenz und Feedback.

Die erste Stufe der Lösung besteht darin, der Seite Folgendes hinzuzufügen:

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

Der Inhalt von fresh.htmlist nicht wichtig, daher sollte Folgendes ausreichen:

<!-- fresh.html -->
<HTML><BODY></BODY></HTML>

Wenn clientseitiger Code die Seite aktualisiert, muss die Änderung wie folgt gekennzeichnet werden:

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.htmlerledigt die ganze Arbeit: Wenn es geladen ist, ruft es die reload_stale_pageFunktion auf, die die Seite bei Bedarf aktualisiert. Das erste Mal, wenn es geladen wird (dh nachdem die Änderung vorgenommen wurde, wird die reload_stale_pageFunktion nichts tun.)

<!-- stale.html -->
<HTML><BODY>
<SCRIPT type="text/javascript">window.parent.reload_stale_page();</SCRIPT>
</BODY></HTML>

Nach meinen (minimalen) Tests in dieser Phase scheint dies wie gewünscht zu funktionieren. Habe ich etwas übersehen?


Nicht das ich wüsste, aber ich habe es nicht vollständig getestet. getElementById wird in einigen älteren Browsern nicht unterstützt, aber es ist einfach, es bei Bedarf gegen jquery oder etwas anderes auszutauschen.
Tom

2

Sie können es mit dem Ereignis onbeforeunload lösen :

window.onbeforeunload = function () { }

Wenn Sie eine leere Event-Manager-Funktion vor dem Laden haben , wird die Seite bei jedem Zugriff neu erstellt. Javascripts werden erneut ausgeführt, serverseitige Skripte werden erneut ausgeführt, die Seite wird so erstellt, als ob der Benutzer sie zum ersten Mal aufgerufen hätte, selbst wenn der Benutzer die Seite nur durch Drücken der Zurück- oder Vorwärts-Schaltfläche aufgerufen hätte .

Hier ist der vollständige Code eines Beispiels:

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

Probieren Sie es aus, navigieren Sie auf dieser Seite weg und kehren Sie dann mit den Schaltflächen "Zurück" oder "Weiter" in Ihrem Browser zurück.

Es funktioniert gut in IE, FF und Chrome.

Natürlich können Sie in der Funktion myfun tun, was Sie wollen .

Weitere Informationen: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript


Arbeitet in Safari für mich
Jakob

2

Sie können localStorage oder sessionStorage ( http://www.w3schools.com/html/html5_webstorage.asp ) verwenden, um ein Flag zu setzen (anstatt ein verstecktes Formular zu verwenden).


Es ist eine gute Problemumgehung, aber wie geht es Ihnen, wenn er dies jedes Mal erkennen möchte, wenn ich die Site geöffnet und geschlossen habe, muss ich erst erkennen, wann ich sie geöffnet habe und zurückgehen, bevor ich sie schließe
Elbaz

1

Verwendung dieser Seite, insbesondere Einbeziehung des Kommentars von @sajith zur Antwort von @Nick White und dieser Seite: 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

Hier ist eine jQuery-Version. Ich muss es einige Male verwenden, da Safari Desktop / Mobile den Cache handhabt, wenn ein Benutzer die Zurück-Taste drückt.

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

Scheint in Chrome nicht zu funktionieren, soweit ich das beurteilen kann. Ein console.log wird nur in der else-Anweisung ausgelöst (zum Testen hinzugefügt), unabhängig davon, wie ich auf die Seite zugreife.
Luke

0

Ich bin heute auf ein ähnliches Problem gestoßen und habe es mit localStorage gelöst (hier mit ein bisschen 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');
    }

});

Si im Grunde:

Wenn der Benutzer das Formular absendet, legen wir auf Seite 1 in localStorage den Wert "Schritte" fest, um anzugeben, welchen Schritt der Benutzer unternommen hat. Gleichzeitig starten wir eine Funktion mit Timeout, die prüft, ob dieser Wert geändert wurde (z. B. 10 Mal / Sekunde).

Auf Seite 2 ändern wir diesen Wert sofort.

Wenn der Benutzer die Schaltfläche "Zurück" verwendet und der Browser Seite 1 in dem Zustand wiederherstellt, in dem wir sie verlassen haben, wird die Funktion "checkSteps" weiterhin ausgeführt und kann feststellen, dass der Wert in "localStorage" geändert wurde (und entsprechende Maßnahmen ergreifen kann) ). Sobald diese Prüfung ihren Zweck erfüllt hat, müssen Sie sie nicht mehr ausführen, sodass wir setTimeout einfach nicht mehr verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.