Zapobiegaj automatycznemu przewijaniu przeglądarki podczas odświeżania

96

Jeśli przejdziesz do strony a i przewiniesz, strona odświeży się w miejscu, w którym ją zostawiłeś. Jest to świetne, jednak dzieje się tak również na stronach, na których adres URL znajduje się zakotwiczenie. Przykładem może być kliknięcie linku http://example.com/post/244#comment5i odświeżenie strony po rozejrzeniu się, nie byłbyś w kotwicy i strona przeskakuje. Czy jest jakiś sposób, aby temu zapobiec za pomocą javascript? Aby nieważne, co zawsze kierować do kotwicy.

ThomasReggi
źródło
Czy rozwiązanie jQuery jest w porządku, czy chcesz zwykłego js?
mrtsherman

Odpowiedzi:

16

To rozwiązanie nie jest już zalecane ze względu na zmiany w zachowaniu przeglądarki. Zobacz inne odpowiedzi.

Zasadniczo, jeśli używana jest kotwica, łączymy się ze zdarzeniem przewijania systemu Windows. Chodzi o to, że pierwsze zdarzenie przewijania musi należeć do automatycznego ponownego pozycjonowania wykonywanego przez przeglądarkę. Kiedy to nastąpi, dokonujemy własnej zmiany pozycji, a następnie usuwamy powiązane zdarzenie. Zapobiega to zepsuciu systemu przez kolejne przewijanie stron.

$(document).ready(function() {
    if (window.location.hash) { 
        //bind to scroll function
        $(document).scroll( function() {
            var hash = window.location.hash
            var hashName = hash.substring(1, hash.length);
            var element;

            //if element has this id then scroll to it
            if ($(hash).length != 0) {
                element = $(hash);
            }
            //catch cases of links that use anchor name
            else if ($('a[name="' + hashName + '"]').length != 0)
            {
                //just use the first one in case there are multiples
                element = $('a[name="' + hashName + '"]:first');
            }

            //if we have a target then go to it
            if (element != undefined) {
                window.scrollTo(0, element.position().top);
            }
            //unbind the scroll event
            $(document).unbind("scroll");
        });
    }

});
mrtsherman
źródło
Myślę, że jeden przypadek użycia, który powinien zostać uwzględniony, to sytuacja, gdy użytkownik przewija stronę, zanim nastąpi automatyczne przewijanie. O ile pamiętam, automatyczne przewijanie następuje dopiero po całkowitym załadowaniu strony. Jeśli użytkownik przewinie wcześniej, automatyczne przewijanie zostanie anulowane. Potrzebny byłby więc sposób na odróżnienie przewijania inicjowanego przez użytkownika od przewijania inicjowanego przez przeglądarkę. Nie wiem, jak to zrobić, ale z tego co pamiętam jest to możliwe.
mrtsherman
1
Booyah! To był fajny problem późnej nocy. Jednak mówię szefowi, że to twoja wina, kiedy zasypiam przy biurku. Właśnie dokonałem szybkiej zmiany, aby usunąć instrukcję powrotu. To przeszkadzało w rozpinaniu, które dodałem dla zdarzenia przewijania.
mrtsherman,
Początkowo otrzymałem to działając w małym podstawowym pliku przykładowym, aby to sprawdzić. Kiedy potwierdziłem, że zadziałało, zdziwiło mnie, że nie działa w ramach mojego projektu. Dzięki procesowi eliminacji udało mi się znaleźć w moim pliku css jedną deklarację stylu, która powodowała błąd. Było to zastosowanie zewnętrznej czcionki. Zapakowałem twój kod w funkcję i teraz przekazuję go do programu obsługi $ (window) .load () w module obsługi doc.ready. Wydaje się, że teraz działa (z niewielkim migotaniem początkowej strony). Dzięki za kod! Daj mi znać, czy jest to solidna poprawka, czy nie.
ThomasReggi,
1
Nie zadziała, jeśli masz zawartość, która wczytuje się po załadowaniu strony; Np .: posiadanie 2 elementów div, które zostaną wypełnione z Ajax banerami.
Decebal
@FlashThunder - czy możesz zdefiniować „nie działa”? Opublikować wiadomość konsoli?
mrtsherman
153

W Chrome, nawet jeśli wymusisz scrollTop na 0, przeskoczy on później po pierwszym zdarzeniu przewijania.

Powinieneś powiązać zwój z tym:

$(window).on('beforeunload', function() {
    $(window).scrollTop(0);
});

Tak więc przeglądarka jest oszukiwana, by uwierzyć, że było to na początku przed odświeżeniem.

josetapadas
źródło
5
O wiele bardziej przydatna niż zaakceptowana odpowiedź, jeśli nie chcesz bawić się przewijaniem.
Dan Abramov
2
To nie działa w Chrome 33. To znaczy przewija do góry przed załadowaniem nowej strony. Jednak przeglądarka nadal w jakiś sposób pamięta poprzednią pozycję przewijania i wykonuje to samo automatyczne przewijanie do tej pozycji.
Haralan Dobrev
1
Testowane na Chrome 36, Firefox 30 i IE 11. Działa bardzo dobrze!
Fizzix
25
W przypadku implementacji innej niż jQuery: window.onbeforeunload = function(){ window.scrollTo(0,0); }
ProfNandaa,
5
Dlaczego wybrałeś zdarzenie „beforeunload” zamiast „unload”. Z moich testów wynika, że ​​ostatni pozwala uniknąć przeskoczenia na górę, zanim strona zostanie naprawdę rozładowana przez przeglądarkę.
Aleksandr Zonov
77

Aby wyłączyć automatyczne przywracanie przewijania, po prostu dodaj ten tag do sekcji nagłówka.

<script>history.scrollRestoration = "manual"</script>

Nie jest obsługiwany przez IE. Zgodność z przeglądarkami.

imos
źródło
3
To byłaby najlepsza odpowiedź, gdyby była dostępna w IE / Edge. Możesz jednak głosować na wdrożenie tutaj: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
The Chewy
4
To powinna być naprawdę prawidłowa odpowiedź w 2019 roku. Żadna inna metoda nie działa w 100%.
Limbo
2
Potwierdzam, że to najlepsze rozwiązanie. Inne rozwiązania tutaj nie działają w Mobile Safari i mogą być szalone. To działa doskonale.
user3330820
22

Po wielu niepowodzeniach w końcu udało mi się załatwić sprawę. anzo ma tutaj rację, ponieważ użycie beforeunloadspowoduje, że strona przeskoczy na górę, gdy użytkownik ponownie załaduje stronę lub kliknie łącze. Więc unloadjest to jasny sposób, aby to zrobić.

$(window).on('unload', function() {
   $(window).scrollTop(0);
});

Sposób Javascript (dzięki ProfNandaa ):

window.onunload = function(){ window.scrollTo(0,0); }

EDYCJA: 16/07/2015

Problem ze skokiem jest nadal obecny w Firefoksie, nawet w unloadprzypadku zdarzenia.

Janaka Dombawela
źródło
3
To rozwiązanie jest znacznie lepsze niż beforeunloadrozwiązanie, ponieważ zapobiega przeskakiwaniu na górę strony po przeładowaniach i kliknięciach kotwicy.
BradGreens,
1
@BradGreens W nowoczesnym Chrome zdarzenie onunload jest również wyzwalane, gdy użytkownik przełączy się na inne karty, co jest nieoczekiwane. onbeforeunload jest nadal poprawnym obejściem.
Telvin Nguyen
@TelvinNguyen Czy możesz podać jakieś źródło informacji na ten temat? Przetestowałem to na Google Chrome 72 i nadal działa dobrze.
Janaka Dombawela
@JanakaDombawela To, co powiedziałem: Zmiana nowej karty, która spowodowałaby problem, jest nieprawidłowa. Jednak możesz zobaczyć, że zdarzenie onunload w tym przykładzie nie jest wyzwalane poprawnie, nawet w przypadku jQuery 1.9.1 vs jQuery 1.8.3. onunload jest zawodny. jsfiddle.net/6s4jhdug/3 (1.8.3) jsfiddle.net/frt45ue9 (1.9.1)
Telvin Nguyen
3

Oto bardziej ogólne podejście. Zamiast próbować zapobiec przewijaniu się przeglądarki (lub przeskakiwaniu na górę, jak by to wyglądało), po prostu przywracam poprzednią pozycję na stronie. To znaczy, że rejestruję bieżące przesunięcie Y strony w localStorage i przewijam do tej pozycji po załadowaniu strony.

function storePagePosition() {
  var page_y = window.pageYOffset;
  localStorage.setItem("page_y", page_y);
}


window.addEventListener("scroll", storePagePosition);


var currentPageY;

try {
  currentPageY = localStorage.getItem("page_y");

  if (currentPageY === undefined) {
    localStorage.setItem("page_y") = 0;
  }

  window.scrollTo( 0, currentPageY );
} catch (e) {
    // no localStorage available
}
Oliver Schafeld
źródło
2

Możesz po prostu wstawić # na końcu, aby strona załadowała się na górze.

Działa na wszystkich przeglądarkach mobilnych i stacjonarnych, ponieważ jest takie proste.

$(document).ready(function() {
var url = window.location.href;
console.log(url);
if( url.indexOf('#') < 0 ) {
    window.location.replace(url + "#");
} else {
    window.location.replace(url);
}

});

// To ładuje stronę z # na końcu.

Daut
źródło
Jeśli spróbuję tego bezpośrednio na moim serwerze, działa to jak magia. Ale mój cms daje mi błąd marży. Nie wiem, co to jest.
alice
1
jeśli używasz wordpress, zmień $ na jQuery
Herzlin
1

To działa dla mnie.

    //Reset scroll top

    history.scrollRestoration = "manual"

    $(window).on('beforeunload', function(){
          $(window).scrollTop(0);
    });
Alex dobrze się bawi
źródło
-2

Powinieneś być w stanie.

Podczas ładowania sprawdź, czy window.location.hashma wartość. Jeśli tak, weź element z identyfikatorem, który pasuje do wartości skrótu. Znajdź pozycję elementu (rekurencyjne wywołania offsetTop / offsetLeft), a następnie przekaż te wartości do window.scrollTo(x, y)metody.

Powinno to przewinąć stronę do żądanego elementu.

nikmd23
źródło
3
Nie przeszkadza to przeglądarkom w wykonywaniu automatycznego przewijania. O to chodzi w tym pytaniu.
Haralan Dobrev