W mojej aplikacji Angular 2, gdy przewijam stronę w dół i klikam link u dołu strony, zmienia trasę i zabiera mnie do następnej strony, ale nie przewija do góry strony. W rezultacie, jeśli pierwsza strona jest długa, a druga strona ma niewiele treści, sprawia wrażenie, że druga strona nie ma zawartości. Ponieważ zawartość jest widoczna tylko wtedy, gdy użytkownik przewinie do góry strony.
Mogę przewinąć okno do góry strony w ngInit komponentu, ale czy jest jakieś lepsze rozwiązanie, które może automatycznie obsługiwać wszystkie trasy w mojej aplikacji?
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
Odpowiedzi:
Możesz zarejestrować odbiornik zmiany trasy w głównym komponencie i przewinąć do góry w przypadku zmian trasy.
źródło
window.scrollTo(0, 0)
jest bardziej zwięzładocument.body.scrollTop = 0;
i czytelniejsza IMO.$("body").animate({ scrollTop: 0 }, 1000);
zamiastwindow.scrollTo(0, 0)
animować płynne przewijanie do góryKątowy 6.1 i nowsze :
Angular 6.1 (wydany w dniu 2018-07-25) dodał wbudowaną obsługę tego problemu, poprzez funkcję o nazwie „Przywracanie pozycji przewijania routera”. Jak opisano w oficjalnym blogu Angular , wystarczy włączyć to w konfiguracji routera w następujący sposób:
Ponadto blog stwierdza: „Oczekuje się, że stanie się to domyślną wersją w przyszłym wydaniu głównym”. Do tej pory tak się nie stało (od wersji Angular 8.2), ale ostatecznie nie będziesz musiał nic robić w kodzie, a to po prostu będzie działać poprawnie po wyjęciu z pudełka.
Więcej informacji na temat tej funkcji i sposobu dostosowywania tego zachowania można znaleźć w oficjalnych dokumentach .
Angular 6.0 i wcześniejsze :
Podczas gdy doskonała odpowiedź @ GuilhermeMeireles rozwiązuje pierwotny problem, wprowadza nowy, przerywając normalne zachowanie, którego oczekujesz podczas nawigacji do tyłu lub do przodu (za pomocą przycisków przeglądarki lub poprzez lokalizację w kodzie). Oczekiwanym zachowaniem jest to, że po przejściu z powrotem na stronę powinna ona pozostać przewinięta w dół do tego samego miejsca, w którym znajdowała się po kliknięciu łącza, ale przewijanie do góry po przybyciu na każdą stronę oczywiście łamie to oczekiwanie.
Poniższy kod rozszerza logikę do wykrywania tego rodzaju nawigacji, subskrybując sekwencję PopStateEvent lokalizacji i pomijając logikę przewijania do góry, jeśli nowo przybyta strona jest wynikiem takiego zdarzenia.
Jeśli strona, z której nawigujesz, jest wystarczająco długa, aby pokryć całą rzutnię, pozycja przewijania jest przywracana automatycznie, ale jak słusznie zauważył @JordanNelson, jeśli strona jest krótsza, musisz śledzić oryginalną pozycję przewijania i przywrócić ją wyraźnie po powrocie na stronę. Zaktualizowana wersja kodu obejmuje również ten przypadek, zawsze jawnie przywracając pozycję przewijania.
źródło
body
?Z Angular 6.1 możesz teraz uniknąć kłopotów i przejść
extraOptions
do swojegoRouterModule.forRoot()
jako drugiego parametru i możesz ustawićscrollPositionRestoration: enabled
Angularowi, aby przewinął do góry, gdy zmienia się trasa.Domyślnie znajdziesz to w
app-routing.module.ts
:Angular Official Docs
źródło
Możesz napisać to bardziej zwięźle, korzystając z obserwowalnej
filter
metody:Jeśli masz problemy z przewijaniem do góry podczas korzystania z sidenav Angular Material 2, to pomoże. W oknie lub treści dokumentu nie będzie paska przewijania, więc musisz pobrać
sidenav
kontener zawartości i przewinąć ten element, w przeciwnym razie spróbuj przewinąć okno jako domyślne.Ponadto, Angular CDK v6.x ma teraz pakiet przewijania, który może pomóc w obsłudze przewijania.
źródło
document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
Jeśli masz renderowanie po stronie serwera, powinieneś uważać, aby nie uruchamiać kodu
windows
na serwerze, na którym ta zmienna nie istnieje. Spowodowałoby to uszkodzenie kodu.isPlatformBrowser
to funkcja używana do sprawdzania, czy bieżąca platforma, na której renderowana jest aplikacja, jest przeglądarką. Dajemy to zastrzykplatformId
.Można również sprawdzić, czy istnieje zmienna
windows
, aby być bezpiecznym, tak jak to:źródło
PLATFORM_ID
wconstructor
i podać tę wartość jako parametr deisPlatformBrowser
metody?isPlatformBrowser
jest funkcją i zawsze będzie prawdą. Zredagowałem to teraz.po prostu zrób to łatwo dzięki akcji kliknięcia
w głównym składniku html uczyń odniesienie #scrollContainer
w głównym składniku .ts
źródło
scrollContainer
pierwszym węźle, być może trzeba będzie trochę wykopać w obiekcie, dla mnie tak naprawdę to działałoscrollContainer .scrollable._elementRef.nativeElement.scrollTop = 0
Angular niedawno wprowadził nową funkcję, wewnątrz modułu routingu kątowego wprowadzono zmiany jak poniżej
źródło
Najlepsza odpowiedź znajduje się w dyskusji Angular GitHub ( zmiana trasy nie przewija do góry na nowej stronie ).
app.component.html
app.component.ts
Pełne podziękowania dla JoniJnm ( oryginalny post )
źródło
Możesz dodać hak cyklu życia AfterViewInit do swojego komponentu.
źródło
Od wersji Angular 6.1 router udostępnia opcję konfiguracji o nazwie
scrollPositionRestoration
, która została zaprojektowana w celu zaspokojenia tego scenariusza.źródło
Jeśli potrzebujesz po prostu przewinąć stronę do góry, możesz to zrobić (nie najlepsze rozwiązanie, ale szybkie)
źródło
Oto rozwiązanie, które wymyśliłem. Połączyłem LocationStrategy ze zdarzeniami routera. Korzystanie z LocationStrategy, aby ustawić wartość logiczną, aby wiedzieć, kiedy użytkownik przegląda historię przeglądarki. W ten sposób nie muszę przechowywać wielu adresów URL i y-przewijania danych (które i tak nie działają dobrze, ponieważ każde dane są zastępowane na podstawie adresu URL). Rozwiązuje to również przypadek na krawędzi, gdy użytkownik decyduje się przytrzymać przycisk Wstecz lub Dalej w przeglądarce i przewija do tyłu lub do przodu wiele stron zamiast tylko jednej.
PS Testowałem tylko na najnowszej wersji IE, Chrome, FireFox, Safari i Opera (od tego postu).
Mam nadzieję że to pomoże.
źródło
To rozwiązanie jest oparte na rozwiązaniach @ FernandoEcheverria i @ GuilhermeMeireles, ale jest bardziej zwięzłe i działa z mechanizmami popstate, które zapewnia router Angular. Pozwala to na przechowywanie i przywracanie poziomu przewijania wielu kolejnych nawigacji.
Przechowujemy pozycje przewijania dla każdego stanu nawigacji na mapie
scrollLevels
. Gdy nie jest to wydarzenie popstate, identyfikator stanu, który ma zamiar zostać przywrócona jest dostarczany przez Kątowymi Routerevent.restoredState.navigationId
. Jest to następnie wykorzystywane do uzyskania ostatniego poziomu przewijania tego stanuscrollLevels
.Jeśli nie ma zapisanego poziomu przewijania dla trasy, przewinie się do góry, jak można się spodziewać.
źródło
scrollTop
vsscrollY
.Oprócz doskonałej odpowiedzi udzielonej przez @Guilherme Meireles, jak pokazano poniżej, możesz ulepszyć swoją implementację, dodając płynne przewijanie, jak pokazano poniżej
następnie dodaj poniższy fragment
do twoich styles.css
źródło
w przypadku safari na iPhonie / iPodzie możesz owinąć setTimeout
źródło
height: 100vh + 1px;
Cześć chłopaki, to działa dla mnie pod kątem 4. Musisz tylko odwołać się do rodzica, aby przewinąć przy zmianie routera`
layout.component.pug
layout.component.ts
źródło
@Fernando Echeverria świetnie! ale ten kod nie działa w routerze skrótu lub leniwym routerze. ponieważ nie powodują zmian lokalizacji. mogę spróbować:
źródło
Korzystanie z
Router
samego siebie spowoduje problemy, których nie można całkowicie rozwiązać, aby utrzymać spójne działanie przeglądarki. Moim zdaniem najlepszą metodą jest po prostu użycie niestandardowegodirective
i pozwolenie na zresetowanie przewijania po kliknięciu. Dobrą rzeczą jest to, że jeśli jesteś na tym samymurl
, co klikasz, strona również przewinie się do góry. Jest to zgodne ze zwykłymi stronami internetowymi. Podstawowydirective
może wyglądać mniej więcej tak:Przy następującym zastosowaniu:
To wystarczy w większości przypadków użycia, ale mogę sobie wyobrazić kilka problemów, które mogą z tego wyniknąć:
universal
powodu użyciawindow
Naprawdę dość łatwo jest rozwiązać te problemy:
Uwzględnia to większość przypadków użycia, przy takim samym użyciu jak podstawowy, z tą zaletą, że włącza / wyłącza:
reklamy, nie czytaj, jeśli nie chcesz być reklamowany
Można wprowadzić kolejne ulepszenie, aby sprawdzić, czy przeglądarka obsługuje
passive
zdarzenia. To skomplikuje kod jeszcze bardziej i jest nieco niejasne, jeśli chcesz zaimplementować je wszystkie w swoich niestandardowych dyrektywach / szablonach. Dlatego napisałem małą bibliotekę, której można użyć do rozwiązania tych problemów. Aby mieć taką samą funkcjonalność jak powyżej oraz z dodanympassive
zdarzeniem, możesz zmienić dyrektywę na to, jeśli korzystasz zng-event-options
biblioteki. Logika znajduje się wewnątrzclick.pnb
detektora:źródło
To działało dla mnie najlepiej dla wszystkich zmian nawigacji, w tym nawigacji skrótowej
źródło
Główną ideą tego kodu jest przechowywanie wszystkich odwiedzonych adresów URL wraz z odpowiednimi danymi scrollY w tablicy. Za każdym razem, gdy użytkownik opuszcza stronę (NavigationStart), tablica ta jest aktualizowana. Za każdym razem, gdy użytkownik wchodzi na nową stronę (NavigationEnd), decydujemy się przywrócić pozycję Y lub nie, w zależności od tego, jak dojdziemy do tej strony. Jeśli użyto odświeżenia na jakiejś stronie, przewijamy do 0. Jeśli użyto funkcji wstecz / do przodu przeglądarki, przewijamy do Y zapisanego w naszej tablicy. Przepraszam za mój angielski :)
źródło
window.scrollTo()
nie działa na mnie w kątowym 5, więc użyłemdocument.body.scrollTop
jak,źródło
Jeśli ładujesz różne komponenty tą samą trasą, możesz użyć ViewportScroller, aby osiągnąć to samo.
źródło
przewiń okno do góry
Zarówno window.pageYOffset, jak i document.documentElement.scrollTop zwraca ten sam wynik we wszystkich przypadkach. window.pageYOffset nie jest obsługiwany poniżej IE 9.
app.component.ts
app.component.html
źródło