webentwicklung-frage-antwort-db.com.de

Abfangen des Aufrufs der Schaltfläche "Zurück" in meiner AJAX Anwendung

Ich habe eine AJAX App. Ein Benutzer klickt auf eine Schaltfläche und die Anzeige der Seite ändert sich. Er klickt auf die Zurück-Schaltfläche und erwartet, dass der ursprüngliche Zustand wiederhergestellt wird. Stattdessen wird die vorherige Seite aufgerufen in ihrem Browser.

Wie kann ich das Ereignis "Zurück" abfangen und neu zuweisen? Ich habe in Bibliotheken wie RSH gesucht (die ich nicht zur Arbeit bringen konnte ...), und ich habe gehört, dass die Verwendung des Hash-Tags irgendwie hilft, aber ich kann keinen Sinn daraus ziehen.

72
Zack Burt

Ah, der Zurück-Knopf. Sie könnten sich vorstellen, dass "back" ein JavaScript-Ereignis auslöst, das Sie einfach so abbrechen könnten:

document.onHistoryGo = function() { return false; }

Nein so Es gibt einfach kein solches Ereignis.

Wenn Sie wirklich eine Web-App haben (im Gegensatz zu einer Website mit einigen Ajaxy-Funktionen), ist es sinnvoll, die Zurück-Schaltfläche (mit Fragmenten in der URL, wie Sie bereits erwähnt haben) zu übernehmen. Google Mail erledigt dies. Ich spreche davon, wenn Ihre Web-App alles auf einer Seite ist, alles in sich geschlossen.

Die Technik ist einfach: Wenn der Benutzer eine Aktion ausführt, die Änderungen vornimmt, wird er zu derselben URL umgeleitet, auf der er sich bereits befindet, jedoch mit einem anderen Hash-Fragment. Z.B.

window.location.hash = "#deleted_something";
...
window.location.hash = "#did_something_else";

Wenn der Gesamtstatus Ihrer Web-App hashbar ist, können Sie hier einen Hash verwenden. Nehmen wir an, Sie haben eine Liste von E-Mails. Vielleicht würden Sie alle ihre IDs und Lese-/Ungelesenen-Status miteinander verknüpfen und einen MD5-Hash verwenden, wobei Sie diesen als Fragment-ID verwenden.

Diese Art der Umleitung (nur Hash) versucht nicht, etwas vom Server abzurufen, fügt jedoch einen Platz in die Verlaufsliste des Browsers ein. Im obigen Beispiel klickt der Benutzer auf "Zurück" und zeigt nun # deleted_something in der Adressleiste an. Sie schlagen wieder zurück und sind immer noch auf Ihrer Seite, aber ohne Hash. Dann zurück und sie eigentlich gehen zurück, wohin sie auch kamen.

Jetzt ist der schwierige Teil jedoch, dass Ihr JavaScript erkennt, wenn der Benutzer zurückschlägt (sodass Sie den Status wiederherstellen können). Alles, was Sie tun, ist, die Fensterposition zu beobachten und zu sehen, wann sie sich ändert. Mit Umfragen. (Ich weiß, igitt, Umfragen. Nun, es gibt momentan nichts besseres browserübergreifendes). Sie können jedoch nicht feststellen, ob sie vorwärts oder rückwärts gingen, sodass Sie mit Ihren Hash-IDs kreativ werden müssen. (Vielleicht ein mit einer Sequenznummer verketteter Hash ...)

Dies ist der Kern des Codes. (So ​​funktioniert auch das jQuery History-Plugin.)

var hash = window.location.hash;
setInterval(function(){
    if (window.location.hash != hash) {
        hash = window.location.hash;
        alert("User went back or forward to application state represented by " + hash);
    }
}, 100);
115
jpsimons

So geben Sie eine aktuelle Antwort auf eine alte (aber beliebte) Frage:

In HTML5 wurden die Methoden history.pushState() und history.replaceState() eingeführt, mit denen Sie Verlaufseinträge hinzufügen bzw. ändern können. Diese Methoden funktionieren in Verbindung mit dem Ereignis window.onpopstate.

Durch die Verwendung von history.pushState() wird der Verweis geändert, der im HTTP-Header für XMLHttpRequest Objekte verwendet wird, die nach dem Ändern des Status erstellt wurden. Der Verweiser ist die URL des Dokuments, dessen Fenster zum Zeitpunkt der Erstellung des Objekts thisXMLHttpRequest ist.

Quelle: Manipulieren des Browserverlaufs vom Mozilla Developer Network.

49
gitaarik

Mit jQuery habe ich eine einfache Lösung gefunden:

$(window).on('hashchange', function() {
    top.location = '#main';
    // Eventually alert the user describing what happened
});

Bisher nur in Google getestet Chrome obwohl.

Dies löste das Problem für meine Web-App, die ebenfalls stark AJAX-basiert ist.

Es ist vielleicht ein bisschen hack'ish - aber ich würde es elegantes Hacken nennen ;-) Immer wenn Sie versuchen, rückwärts zu navigieren, wird ein Hash-Teil in die URI eingefügt, der technisch gesehen das ist, was es dann versucht, rückwärts zu navigieren.

Es fängt sowohl das Klicken der Browser-Taste als auch der Maustaste ab. Und Sie können es auch nicht rückwärts erzwingen, indem Sie mehrmals pro Sekunde klicken. Dies ist ein Problem, das bei Lösungen auftreten würde, die auf setTimeout oder setInterval basieren.

Ich schätze die Erklärung in Darkporters Antwort sehr, aber ich denke, sie kann durch die Verwendung eines " -Hashwechsels verbessert werden. ) "event . Wie in darkporter erläutert, möchten Sie sicherstellen, dass alle Schaltflächen den Wert window.location.hash ändern.

  • Eine Möglichkeit ist die Verwendung von <button> Elemente, und fügen Sie dann Ereignisse hinzu, die dann window.location.hash = "#!somehashstring";.
  • Eine andere Möglichkeit, dies zu tun, besteht darin, nur Links für Ihre Schaltflächen zu verwenden, z. B. <a href="#!somehashstring">Button 1</a>. Der Hash wird automatisch aktualisiert, wenn auf diese Links geklickt wird.

Der Grund, warum ich nach dem Hash-Zeichen ein Ausrufezeichen habe, ist, dass es Googles "Hashbang" -Paradigma erfüllt ( lesen Sie mehr daz ). Dies ist nützlich, wenn Sie von Suchmaschinen indiziert werden möchten. Ihr Hashstring besteht normalerweise aus Name/Wert-Paaren wie #!color=blue&shape=triangle oder eine Liste wie #!/blue/triangle - was auch immer für Ihre Web-App Sinn macht.

Dann müssen Sie nur dieses Codebit hinzufügen, das ausgelöst wird, wenn sich der Hash-Wert ändert (einschließlich , wenn der Zurück-Button gedrückt wird ). Eine Polling-Schleife scheint nicht erforderlich zu sein.

window.addEventListener("hashchange", function(){
    console.log("Hash changed to", window.location.hash);
    // .... Do your thing here...
});

Ich habe nichts anderes getestet als Chrome 36, aber laut caniuse.com , dies sollte in IE8 +, FF21 +, Chrome21 + und den meisten anderen Browsern außer verfügbar sein Opera Mini.

8
Luke

Es ist sehr einfach, die ZURÜCK-Taste des Browsers zu deaktivieren , wie den folgenden JQuery-Code:

// History API 
if( window.history && window.history.pushState ){

  history.pushState( "nohb", null, "" );
  $(window).on( "popstate", function(event){
    if( !event.originalEvent.state ){
      history.pushState( "nohb", null, "" );
      return;
    }
  });
}

Sie können sehen, wie es funktioniert und weitere Beispiele hier dotnsf und hier thecssninja

Vielen Dank !

Aus Datenschutzgründen ist es nicht möglich, die Schaltfläche "Zurück" zu deaktivieren oder den Verlauf des Benutzers zu überprüfen. Es ist jedoch möglich, neue Einträge in diesem Verlauf zu erstellen, ohne die Seiten zu ändern. Immer wenn Ihre AJAX Anwendung den Status ändert, aktualisieren Sie top.location mit einem neuen RI-Fragment .

top.location = "#new-application-state";

Dadurch wird ein neuer Eintrag im Verlaufsstapel des Browsers erstellt. Eine Reihe von AJAX - Bibliotheken behandelt bereits alle langweiligen Details, wie Really Simple History .

4
Matthew

In meiner Situation wollte ich verhindern, dass der Benutzer über die Schaltfläche "Zurück" zur letzten Seite weitergeleitet wird, und stattdessen eine andere Aktion ausführen. Mit dem Ereignis hashchange habe ich eine Lösung gefunden, die für mich funktioniert hat. In diesem Skript wird davon ausgegangen, dass die Seite, auf der Sie es verwenden, noch keinen Hash verwendet, wie in meinem Fall:

var hashChangedCount = -2;
$(window).on("hashchange", function () {
    hashChangedCount++;
    if (top.location.hash == "#main" && hashChangedCount > 0) {
        console.log("Ah ah ah! You didn't say the magic Word!");
    }
    top.location.hash = '#main';
});
top.location.hash = "#";

Das Problem, das ich bei einigen der anderen Antworten hatte, ist, dass das Ereignis hashchange nicht ausgelöst wird. Abhängig von Ihrer Situation kann dies auch für Sie funktionieren.

2
Swisher Sweet

Ich habe eine Möglichkeit gefunden, das normale Verlaufsverhalten zu überschreiben und mithilfe der HTML5-Verlaufs-API unterschiedliche Ereignisse für die Schaltflächen back und forward zu erstellen (dies funktioniert nicht in IE = 9) Dies ist sehr schwierig, aber effektiv, wenn Sie die Schaltflächenereignisse "Zurück" und "Vor" abfangen und so behandeln möchten, wie Sie möchten. Dies kann in einer Reihe von Szenarien hilfreich sein, z Zum Wiedergeben der Vorwärts- und Rückwärts-Tastenklicks auf dem Remote-Computer.

Folgendes würde das Verhalten der Schaltflächen "Zurück" und "Vorwärts" außer Kraft setzen:

var myHistoryOverride = new HistoryButtonOverride(function()
{
    console.log("Back Button Pressed");
    return true;
},
function()
{
    console.log("Forward Button Pressed");
    return true;
});

Wenn Sie in einer dieser Rückruffunktionen den Wert false zurückgegeben haben, können Sie dem Browser gestatten, mit einem normalen Vor-/Zurück-Vorgang fortzufahren und Ihre Seite zu verlassen.

Hier ist das vollständige Skript erforderlich:

function HistoryButtonOverride(BackButtonPressed, ForwardButtonPressed)
{
    var Reset = function ()
    {
        if (history.state == null)
            return;
        if (history.state.customHistoryStage == 1)
            history.forward();
        else if (history.state.customHistoryStage == 3)
            history.back();
    }
    var BuildURLWithHash = function ()
    {
        // The URLs of our 3 history states must have hash strings in them so that back and forward events never cause a page reload.
        return location.Origin + location.pathname + location.search + (location.hash && location.hash.length > 1 ? location.hash : "#");
    }
    if (history.state == null)
    {
        // This is the first page load. Inject new history states to help identify back/forward button presses.
        var initialHistoryLength = history.length;
        history.replaceState({ customHistoryStage: 1, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
        history.pushState({ customHistoryStage: 2, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
        history.pushState({ customHistoryStage: 3, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
        history.back();
    }
    else if (history.state.customHistoryStage == 1)
        history.forward();
    else if (history.state.customHistoryStage == 3)
        history.back();

    $(window).bind("popstate", function ()
    {
        // Called when history navigation occurs.
        if (history.state == null)
            return;
        if (history.state.customHistoryStage == 1)
        {
            if (typeof BackButtonPressed == "function" && BackButtonPressed())
            {
                Reset();
                return;
            }
            if (history.state.initialHistoryLength > 1)
                history.back(); // There is back-history to go to.
            else
                history.forward(); // No back-history to go to, so undo the back operation.
        }
        else if (history.state.customHistoryStage == 3)
        {
            if (typeof ForwardButtonPressed == "function" && ForwardButtonPressed())
            {
                Reset();
                return;
            }
            if (history.length > history.state.initialHistoryLength + 2)
                history.forward(); // There is forward-history to go to.
            else
                history.back(); // No forward-history to go to, so undo the forward operation.
        }
    });
};

Dies funktioniert nach einem einfachen Konzept. Wenn unsere Seite geladen wird, erstellen wir drei unterschiedliche Verlaufszustände (mit den Nummern 1, 2 und 3) und navigieren den Browser zu Zustand 2. Da Zustand 2 in der Mitte liegt, versetzt uns das nächste Verlaufsnavigationsereignis entweder in Zustand 1 oder 3, und daraus können wir bestimmen, in welche Richtung der Benutzer gedrückt hat. Und einfach so haben wir ein Vorwärts- oder Rückwärts-Schaltflächenereignis abgefangen. Wir behandeln es dann, wie wir wollen, und kehren zu Zustand Nummer 2 zurück, damit wir das nächste Ereignis der Verlaufsnavigation erfassen können.

Offensichtlich müssten Sie die Methoden history.replaceState und history.pushState nicht verwenden, während Sie das Script HistoryButtonOverride verwenden, sonst würden Sie es unterbrechen.

2
Brian

Die Zurück-Schaltfläche in den Browsern versucht normalerweise, zur vorherigen Adresse zurückzukehren. es gibt kein natives Ereignis, bei dem die Schaltfläche "Zurück" gedrückt wurde in Browser-Javascript, aber Sie können es hacken, indem Sie mit Standort und Hash spielen, um Ihren App-Status zu ändern.

stellen Sie sich die einfache App mit zwei Ansichten vor:

  • standardansicht mit einer Schaltfläche zum Abrufen
  • ergebnisansicht

folgen Sie diesem Beispielcode, um es zu implementieren:

function goToView (viewName) {
  // before you want to change the view, you have to change window.location.hash.
  // it allows you to go back to the previous view with the back button.
  // so use this function to change your view instead of directly do the job.
  // page parameter is your key to understand what view must be load after this.

  window.location.hash = page
}

function loadView (viewName) {
    // change dom here based on viewName, for example:

    switch (viewName) {
      case 'index':
        document.getElementById('result').style.display = 'none'
        document.getElementById('index').style.display = 'block'
        break
      case 'result':
        document.getElementById('index').style.display = 'none'
        document.getElementById('result').style.display = 'block'
        break
      default:
        document.write('404')
    }
}

window.addEventListener('hashchange', (event) => {
  // oh, the hash is changed! it means we should do our job.
  const viewName = window.location.hash.replace('#', '') || 'index'

  // load that view
  loadView(viewName)
})


// load requested view at start.
if (!window.location.hash) {
  // go to default view if there is no request.
  goToView('index')
} else {
  // load requested view.
  loadView(window.location.hash.replace('#', ''))
}
1
Nainemom

Ich mache so etwas. Ich behalte ein Array mit vorherigen App-Status.

Initiiert als:

var backstack = [];

Dann achte ich auf Änderungen im Standort-Hash und wenn sich dieser ändert, tue ich Folgendes:

if (backstack.length > 1 && backstack[backstack.length - 2] == newHash) {
    // Back button was probably pressed
    backstack.pop();
} else
    backstack.Push(newHash);

Auf diese Weise kann ich auf einfache Weise den Verlauf der Benutzer verfolgen. Wenn ich nun einen Zurück-Button in der App implementieren möchte (nicht im Browser-Botton), lasse ich es einfach tun:

window.location.hash = backstack.pop();
0
Trenskow