Wie kann ich window.location.hash aktualisieren, ohne das Dokument zu überspringen?

162

Ich habe auf meiner Website ein Schiebefeld eingerichtet.

Als die Animation beendet war, stellte ich den Hash so ein

function() {
   window.location.hash = id;
}

(Dies ist ein Rückruf, und der idwird früher zugewiesen).

Dies funktioniert gut, damit der Benutzer das Bedienfeld mit einem Lesezeichen versehen kann und auch die Nicht-JavaScript-Version funktioniert.

Wenn ich jedoch den Hash aktualisiere, springt der Browser zum Speicherort. Ich denke, das ist erwartetes Verhalten.

Meine Frage ist: Wie kann ich das verhindern? Das heißt , wie kann ich den Hash - Fenster ändern, aber nicht den Browser blättern zu dem Element, wenn der Hash existiert? So event.preventDefault()etwas?

Ich verwende jQuery 1.4 und das scrollTo-Plugin .

Danke vielmals!

Aktualisieren

Hier ist der Code, der das Panel ändert.

$('#something a').click(function(event) {
    event.preventDefault();
    var link = $(this);
    var id = link[0].hash;

    $('#slider').scrollTo(id, 800, {
        onAfter: function() {

            link.parents('li').siblings().removeClass('active');
            link.parent().addClass('active');
            window.location.hash = id;

            }
    });
});
Alex
quelle
2
Ich nehme an, Sie haben es versucht event.preventDefault():)
Marko
@ Marko Ich weiß nicht, wo ich es platzieren soll!
Alex
Können Sie den Rest Ihres Codes posten?
Marko
@ Marko Ivanovski Ich denke nicht, dass es relevant ist, aber ich werde sehen, was ich tun kann.
Alex
3
@Gareth Ich glaube nicht, dass es einen Platz dafür gibt, weil es passiert, sobald ich den Hash aktualisiere.
Alex

Antworten:

261

Es gibt eine Problemumgehung, indem Sie die Verlaufs-API in modernen Browsern verwenden und auf alte zurückgreifen:

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}

Der Kredit geht an Lea Verou

Attila Fulop
quelle
Dies ist meiner Meinung nach die bessere Antwort.
Greg Annandale
10
Beachten Sie, dass pushState den Nebeneffekt (eingerückt) hat, dem Browserverlaufsstapel einen Status hinzuzufügen. Mit anderen Worten, wenn der Benutzer auf die Schaltfläche "Zurück" klickt, geschieht nichts, es sei denn, Sie fügen auch einen Popstate-Ereignis-Listener hinzu.
David Cook
32
@DavidCook - Wir könnten auch verwenden history.replaceState(was für Hash-Änderungen sinnvoller sein könnte), um die Notwendigkeit eines popstateEreignis-Listeners zu vermeiden .
Jack
Das hat bei mir funktioniert. Ich mag die Auswirkungen der Änderung der Geschichte. Ich möchte die Einschränkung hinzufügen, dass dies das hashchangeEreignis nicht auslöst . Daran musste ich arbeiten.
Jordanien
Warnung! Dies wird kein hashchangeEreignis auslösen
Santiago Arizona
52

Das Problem ist, dass Sie die Datei window.location.hash auf das ID-Attribut eines Elements setzen. Es ist das erwartete Verhalten des Browsers, zu diesem Element zu springen, unabhängig davon, ob Sie "verhindern" (nicht).

Eine Möglichkeit, dies zu umgehen, besteht darin, dem Hash einen beliebigen Wert wie folgt voranzustellen:

window.location.hash = 'panel-' + id.replace('#', '');

Anschließend müssen Sie beim Laden der Seite nur noch nach dem vorangestellten Hash suchen. Als zusätzlichen Bonus können Sie sogar reibungslos dorthin scrollen, da Sie jetzt die Kontrolle über den Hash-Wert haben ...

$(function(){
    var h = window.location.hash.replace('panel-', '');
    if (h) {
        $('#slider').scrollTo(h, 800);
    }
});

Wenn Sie dies benötigen, um jederzeit zu funktionieren (und nicht nur beim ersten Laden der Seite), können Sie eine Funktion verwenden, um Änderungen am Hash-Wert zu überwachen und sofort zum richtigen Element zu springen:

var foundHash;
setInterval(function() {
    var h = window.location.hash.replace('panel-', '');
    if (h && h !== foundHash) {
        $('#slider').scrollTo(h, 800);
        foundHash = h;
    }
}, 100);
Derek Hunziker
quelle
2
Dies ist die einzige Lösung, die tatsächlich die Frage beantwortet - Hashing ohne Springen
zuzulassen
Dies beantwortet wirklich die Frage, die das Hinzufügen und Löschen des beliebigen Werts für den Hash erklärt, um den Sprung gemäß dem Standardverhalten des Browsers zu vermeiden.
Lowtechsun
1
Gute Lösung, schwächt aber die OP-Lösung, da sie die Verwendung von Lesezeichenabschnitten negiert
Samus
27

Günstige und böse Lösung .. Verwenden Sie die hässliche #! Stil.

So stellen Sie es ein:

window.location.hash = '#!' + id;

Um es zu lesen:

id = window.location.hash.replace(/^#!/, '');

Da es nicht mit dem Anker oder der ID auf der Seite übereinstimmt, springt es nicht.

Gavin Brock
quelle
3
Ich musste die Kompatibilität mit IE 7 und einigen mobilen Versionen der Site beibehalten. Diese Lösung war für mich am saubersten. Im Allgemeinen würde ich alle PushState-Lösungen verwenden.
Eric Goodwin
1
Wenn window.location.hash = '#/' + id;Sie den Hash mit: setzen und dann durch : ersetzen, window.location.hash.replace(/^#\//, '#');wird die URL ein wenig projects/#/tab1
verschönert
13

Warum erhalten Sie nicht die aktuelle Bildlaufposition, fügen sie in eine Variable ein, weisen dann den Hash zu und setzen den Bildlauf an die Position zurück, an der er war:

var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;

das sollte funktionieren

user706270
quelle
1
hm, das hat eine Weile für mich funktioniert, aber irgendwann in den letzten Monaten hat das aufgehört, an Firefox zu arbeiten ...
Matchew
10

Ich habe eine Kombination aus Attila Fulop (Lea Verou) -Lösung für moderne Browser und Gavin Brock-Lösung für alte Browser wie folgt verwendet:

if (history.pushState) {
    // IE10, Firefox, Chrome, etc.
    window.history.pushState(null, null, '#' + id);
} else {
    // IE9, IE8, etc
    window.location.hash = '#!' + id;
}

Wie von Gavin Brock beobachtet, müssen Sie die Zeichenfolge (die in diesem Fall das "!" Haben kann oder nicht) wie folgt behandeln, um die ID zurück zu erfassen:

id = window.location.hash.replace(/^#!?/, '');

Vorher habe ich eine ähnliche Lösung wie die von user706270 vorgeschlagene versucht, die jedoch mit Internet Explorer nicht gut funktioniert hat: Da die Javascript-Engine nicht sehr schnell ist, können Sie feststellen, dass der Bildlauf zunimmt und abnimmt, was zu einem unangenehmen visuellen Effekt führt.

Aldemarcalazane
quelle
2

Diese Lösung hat bei mir funktioniert.

Das Problem bei der Einstellung location.hashist, dass die Seite zu dieser ID springt, wenn sie auf der Seite gefunden wird.

Das Problem dabei window.history.pushStateist, dass für jede Registerkarte, auf die der Benutzer klickt, ein Eintrag zum Verlauf hinzugefügt wird. Wenn der Benutzer dann auf die backSchaltfläche klickt , wechselt er zur vorherigen Registerkarte. (Dies kann oder kann nicht sein, was Sie wollen. Es war nicht das, was ich wollte).

Für mich replaceStatewar die bessere Option, da sie nur den aktuellen Verlauf ersetzt. Wenn der Benutzer auf die backSchaltfläche klickt , wechselt er zur vorherigen Seite.

$('#tab-selector').tabs({
  activate: function(e, ui) {
    window.history.replaceState(null, null, ui.newPanel.selector);
  }
});

Überprüfen Sie die Verlaufs-API-Dokumente auf MDN.

Mike Vallano
quelle
1

Ich bin nicht sicher, ob Sie das ursprüngliche Element ändern können, aber wie wäre es, wenn Sie von der Verwendung der ID attr zu etwas anderem wie der Daten-ID wechseln? Dann lesen Sie einfach den Wert der Daten-ID für Ihren Hash-Wert und es wird nicht springen.

Jon B.
quelle
1

Diese Lösung hat bei mir funktioniert

// store the currently selected tab in the hash value
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
$('#myTab a[href="' + hash + '"]').tab('show');

Und mein vollständiger JS-Code ist

$('#myTab a').click(function(e) {
  e.preventDefault();
  $(this).tab('show');
});

// store the currently selected tab in the hash value
$("ul.nav-tabs > li > a").on("shown.bs.tab", function(e) {
  var id = $(e.target).attr("href").substr(1);
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }
   // window.location.hash = '#!' + id;
});

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
// console.log(hash);
$('#myTab a[href="' + hash + '"]').tab('show');
Rohit Dhiman
quelle
0

Bei der Verwendung des Laravel-Frameworks hatte ich einige Probleme mit der Verwendung einer route-> back () -Funktion, da dadurch mein Hash gelöscht wurde. Um meinen Hash zu behalten, habe ich eine einfache Funktion erstellt:

$(function() {   
    if (localStorage.getItem("hash")    ){
     location.hash = localStorage.getItem("hash");
    }
}); 

und ich stelle es in meiner anderen JS-Funktion so ein:

localStorage.setItem("hash", myvalue);

Sie können Ihre lokalen Speicherwerte beliebig benennen. meins benannt hash.

Wenn der Hash auf PAGE1 gesetzt ist und Sie dann zu PAGE2 navigieren; Der Hash wird auf SEITE1 neu erstellt, wenn Sie auf SEITE2 auf Zurück klicken.

Andrew
quelle