Kątowy 2 Przewiń do góry w opcji Zmiana trasy


295

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?


20
Od wersji Angular 6.1 możemy używać {scrollPositionRestoration: 'enabled'} na chętnie ładowanych modułach lub tylko w app.module i będzie on stosowany do wszystkich tras. RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
Manwal

Muito obrigado sua solução funcionou perfeitamente para mim :)
Raphael Godoi

ani jedna osoba nie wymieniła uwagi? ważniejsze niż kiedykolwiek wcześniej jest prawidłowe obsługiwanie ułatwień dostępu / czytników ekranu, a jeśli po prostu przewiniesz do góry bez rozważania skupienia, naciśnięcie następnej karty może przejść do dolnej części ekranu.
Simon_Weaver

Odpowiedzi:


385

Możesz zarejestrować odbiornik zmiany trasy w głównym komponencie i przewinąć do góry w przypadku zmian trasy.

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {
    constructor(private router: Router) { }

    ngOnInit() {
        this.router.events.subscribe((evt) => {
            if (!(evt instanceof NavigationEnd)) {
                return;
            }
            window.scrollTo(0, 0)
        });
    }
}

11
window.scrollTo(0, 0)jest bardziej zwięzła document.body.scrollTop = 0;i czytelniejsza IMO.
Mark E. Haase,

10
Czy ktoś zauważył, że nawet po wdrożeniu tego problemu problem występuje w przeglądarce Safari na iPhonie. jakieś pomysły?
rgk

1
@mehaase Wygląda na to, że Twoja odpowiedź jest najlepsza. Window.body.scrollTop nie działa dla mnie na pulpicie Firefox. Więc dziękuję !
KCarnaille

3
To działało dla mnie, ale psuje domyślne zachowanie przycisku „wstecz”. Wracając pamiętaj poprzednią pozycję przewijania.
JackKalish,

6
To działało !! Chociaż dodałem $("body").animate({ scrollTop: 0 }, 1000);zamiast window.scrollTo(0, 0)animować płynne przewijanie do góry
Manubhargav

360

Ką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:

RouterModule.forRoot(routes, {scrollPositionRestoration: 'enabled'})

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.

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
import { Location, PopStateEvent } from "@angular/common";

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {

    private lastPoppedUrl: string;
    private yScrollStack: number[] = [];

    constructor(private router: Router, private location: Location) { }

    ngOnInit() {
        this.location.subscribe((ev:PopStateEvent) => {
            this.lastPoppedUrl = ev.url;
        });
        this.router.events.subscribe((ev:any) => {
            if (ev instanceof NavigationStart) {
                if (ev.url != this.lastPoppedUrl)
                    this.yScrollStack.push(window.scrollY);
            } else if (ev instanceof NavigationEnd) {
                if (ev.url == this.lastPoppedUrl) {
                    this.lastPoppedUrl = undefined;
                    window.scrollTo(0, this.yScrollStack.pop());
                } else
                    window.scrollTo(0, 0);
            }
        });
    }
}

2
Powinno to nastąpić albo bezpośrednio w komponencie aplikacji, albo w jednym komponencie używanym w nim (a zatem współdzielonym przez całą aplikację). Na przykład umieściłem go w komponencie górnego paska nawigacyjnego. Nie należy uwzględniać wszystkich składników.
Fernando Echeverria

3
Możesz to zrobić, dzięki czemu kod będzie bardziej kompatybilny z innymi platformami nieobsługującymi przeglądarki. Szczegółowe informacje dotyczące implementacji można znaleźć na stackoverflow.com/q/34177221/2858481 .
Fernando Echeverria

3
Po kliknięciu i przytrzymaniu przycisku Wstecz / Dalej w nowoczesnych przeglądarkach pojawi się menu, które umożliwia nawigację do lokalizacji innych niż poprzednio poprzednia / następna. To rozwiązanie się psuje, jeśli to zrobisz. Dla większości jest to przypadek krawędziowy, ale warto o tym wspomnieć.
adamdport


1
Czy istnieje sposób na włączenie „przywracania pozycji przewijania routera” dla elementów zagnieżdżonych lub działa tylko w przypadku body?
vulp

61

Z Angular 6.1 możesz teraz uniknąć kłopotów i przejść extraOptionsdo swojego RouterModule.forRoot()jako drugiego parametru i możesz ustawić scrollPositionRestoration: enabledAngularowi, aby przewinął do góry, gdy zmienia się trasa.

Domyślnie znajdziesz to w app-routing.module.ts:

const routes: Routes = [
  {
    path: '...'
    component: ...
  },
  ...
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'enabled', // Add options right here
    })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Angular Official Docs


3
Mimo że powyższa odpowiedź jest bardziej opisowa, podoba mi się, że ta odpowiedź powiedziała mi dokładnie, dokąd to ma iść
ryanovas

32

Możesz napisać to bardziej zwięźle, korzystając z obserwowalnej filtermetody:

this.router.events.filter(event => event instanceof NavigationEnd).subscribe(() => {
      this.window.scrollTo(0, 0);
});

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ć sidenavkontener zawartości i przewinąć ten element, w przeciwnym razie spróbuj przewinąć okno jako domyślne.

this.router.events.filter(event => event instanceof NavigationEnd)
  .subscribe(() => {
      const contentContainer = document.querySelector('.mat-sidenav-content') || this.window;
      contentContainer.scrollTo(0, 0);
});

Ponadto, Angular CDK v6.x ma teraz pakiet przewijania, który może pomóc w obsłudze przewijania.


2
Świetny! Dla mnie to zadziałało -document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
Amir Tugi

Niezły gość ... w mtpultz & @AmirTugi. Radzenie sobie z tym teraz, a ty przybiłeś go dla mnie, na zdrowie! Prawdopodobnie nieuchronnie skończy się moja nawigacja boczna, ponieważ Materiał 2 nie działa dobrze, gdy pasek narzędzi md jest ustawiony na pozycję: naprawiono (u góry). Chyba, że ​​macie pomysły ... ????
Tim Harker

Może znalazłem moją odpowiedź ... stackoverflow.com/a/40396105/3389046
Tim Harker

16

Jeśli masz renderowanie po stronie serwera, powinieneś uważać, aby nie uruchamiać kodu windowsna serwerze, na którym ta zmienna nie istnieje. Spowodowałoby to uszkodzenie kodu.

export class AppComponent implements OnInit {
  routerSubscription: Subscription;

  constructor(private router: Router,
              @Inject(PLATFORM_ID) private platformId: any) {}

  ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      this.routerSubscription = this.router.events
        .filter(event => event instanceof NavigationEnd)
        .subscribe(event => {
          window.scrollTo(0, 0);
        });
    }
  }

  ngOnDestroy() {
    this.routerSubscription.unsubscribe();
  }
}

isPlatformBrowserto funkcja używana do sprawdzania, czy bieżąca platforma, na której renderowana jest aplikacja, jest przeglądarką. Dajemy to zastrzyk platformId.

Można również sprawdzić, czy istnieje zmienna windows, aby być bezpiecznym, tak jak to:

if (typeof window != 'undefined')

1
Czy nie trzeba wstrzyknąć PLATFORM_IDw constructori podać tę wartość jako parametr de isPlatformBrowsermetody?
Poul Kruijt

1
@PierreDuc Tak, odpowiedź jest błędna. isPlatformBrowserjest funkcją i zawsze będzie prawdą. Zredagowałem to teraz.
Lazar Ljubenović

Dzięki! Teraz jest poprawne! Właśnie zweryfikowałem API: github.com/angular/angular/blob/...
Raptor

13

po prostu zrób to łatwo dzięki akcji kliknięcia

w głównym składniku html uczyń odniesienie #scrollContainer

<div class="main-container" #scrollContainer>
    <router-outlet (activate)="onActivate($event, scrollContainer)"></router-outlet>
</div>

w głównym składniku .ts

onActivate(e, scrollContainer) {
    scrollContainer.scrollTop = 0;
}

Element do przewinięcia może nie znajdować się w scrollContainerpierwszym 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
Byron Lopez

13

Angular niedawno wprowadził nową funkcję, wewnątrz modułu routingu kątowego wprowadzono zmiany jak poniżej

@NgModule({
  imports: [RouterModule.forRoot(routes,{
    scrollPositionRestoration: 'top'
  })],

12

Najlepsza odpowiedź znajduje się w dyskusji Angular GitHub ( zmiana trasy nie przewija do góry na nowej stronie ).

Może chcesz przejść do góry tylko w przypadku zmian routera root (nie u dzieci, ponieważ możesz ładować trasy z leniwym ładowaniem w zestawie tabulatorów)

app.component.html

<router-outlet (deactivate)="onDeactivate()"></router-outlet>

app.component.ts

onDeactivate() {
  document.body.scrollTop = 0;
  // Alternatively, you can scroll to top by using this other call:
  // window.scrollTo(0, 0)
}

Pełne podziękowania dla JoniJnm ( oryginalny post )



7

Od wersji Angular 6.1 router udostępnia opcję konfiguracji o nazwie scrollPositionRestoration, która została zaprojektowana w celu zaspokojenia tego scenariusza.

imports: [
  RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'
  }),
  ...
]

4

Jeśli potrzebujesz po prostu przewinąć stronę do góry, możesz to zrobić (nie najlepsze rozwiązanie, ale szybkie)

document.getElementById('elementId').scrollTop = 0;

4

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.

export class AppComponent implements OnInit {
  isPopState = false;

  constructor(private router: Router, private locStrat: LocationStrategy) { }

  ngOnInit(): void {
    this.locStrat.onPopState(() => {
      this.isPopState = true;
    });

    this.router.events.subscribe(event => {
      // Scroll to top if accessing a page, not via browser history stack
      if (event instanceof NavigationEnd && !this.isPopState) {
        window.scrollTo(0, 0);
        this.isPopState = false;
      }

      // Ensures that isPopState is reset
      if (event instanceof NavigationEnd) {
        this.isPopState = false;
      }
    });
  }
}

4

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 Router event.restoredState.navigationId. Jest to następnie wykorzystywane do uzyskania ostatniego poziomu przewijania tego stanu scrollLevels.

Jeśli nie ma zapisanego poziomu przewijania dla trasy, przewinie się do góry, jak można się spodziewać.

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class AppComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit() {
    const scrollLevels: { [navigationId: number]: number } = {};
    let lastId = 0;
    let restoredId: number;

    this.router.events.subscribe((event: Event) => {

      if (event instanceof NavigationStart) {
        scrollLevels[lastId] = window.scrollY;
        lastId = event.id;
        restoredId = event.restoredState ? event.restoredState.navigationId : undefined;
      }

      if (event instanceof NavigationEnd) {
        if (restoredId) {
          // Optional: Wrap a timeout around the next line to wait for
          // the component to finish loading
          window.scrollTo(0, scrollLevels[restoredId] || 0);
        } else {
          window.scrollTo(0, 0);
        }
      }

    });
  }

}

Niesamowite. Musiałem stworzyć nieco niestandardową wersję, aby przewijać div zamiast okna, ale zadziałało. Jednym z kluczowych różnica była scrollTopvs scrollY.
BBaysinger

4

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

 import { Component, OnInit } from '@angular/core';
    import { Router, NavigationEnd } from '@angular/router';

    @Component({
        selector: 'my-app',
        template: '<ng-content></ng-content>',
    })
    export class MyAppComponent implements OnInit {
        constructor(private router: Router) { }

        ngOnInit() {
            this.router.events.subscribe((evt) => {
                if (!(evt instanceof NavigationEnd)) {
                    return;
                }
                window.scrollTo(0, 0)
            });
        }
    }

następnie dodaj poniższy fragment

 html {
      scroll-behavior: smooth;
    }

do twoich styles.css


1

w przypadku safari na iPhonie / iPodzie możesz owinąć setTimeout

setTimeout(function(){
    window.scrollTo(0, 1);
}, 0);

w moim przypadku wymagało to również ustawienia elementu zawijania strony css; height: 100vh + 1px;
tubbsy 10.03.17

1

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

.wrapper(#outlet="")
    router-outlet((activate)='routerActivate($event,outlet)')

layout.component.ts

 public routerActivate(event,outlet){
    outlet.scrollTop = 0;
 }`

1
wybacz mi lenistwo, że nie zawracam sobie głowy nauką mopsa, ale czy potrafisz przetłumaczyć na HTML?
CodyBugstein

0

@Fernando Echeverria świetnie! ale ten kod nie działa w routerze skrótu lub leniwym routerze. ponieważ nie powodują zmian lokalizacji. mogę spróbować:

private lastRouteUrl: string[] = []
  

ngOnInit(): void {
  this.router.events.subscribe((ev) => {
    const len = this.lastRouteUrl.length
    if (ev instanceof NavigationEnd) {
      this.lastRouteUrl.push(ev.url)
      if (len > 1 && ev.url === this.lastRouteUrl[len - 2]) {
        return
      }
      window.scrollTo(0, 0)
    }
  })
}


0

Korzystanie z Routersamego 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 niestandardowego directivei pozwolenie na zresetowanie przewijania po kliknięciu. Dobrą rzeczą jest to, że jeśli jesteś na tym samym url, co klikasz, strona również przewinie się do góry. Jest to zgodne ze zwykłymi stronami internetowymi. Podstawowy directivemoże wyglądać mniej więcej tak:

import {Directive, HostListener} from '@angular/core';

@Directive({
    selector: '[linkToTop]'
})
export class LinkToTopDirective {

    @HostListener('click')
    onClick(): void {
        window.scrollTo(0, 0);
    }
}

Przy następującym zastosowaniu:

<a routerLink="/" linkToTop></a>

To wystarczy w większości przypadków użycia, ale mogę sobie wyobrazić kilka problemów, które mogą z tego wyniknąć:

  • Nie działa z universalpowodu użyciawindow
  • Mały wpływ na wykrywanie zmian ma szybkość, ponieważ jest uruchamiany przy każdym kliknięciu
  • Nie ma możliwości wyłączenia tej dyrektywy

Naprawdę dość łatwo jest rozwiązać te problemy:

@Directive({
  selector: '[linkToTop]'
})
export class LinkToTopDirective implements OnInit, OnDestroy {

  @Input()
  set linkToTop(active: string | boolean) {
    this.active = typeof active === 'string' ? active.length === 0 : active;
  }

  private active: boolean = true;

  private onClick: EventListener = (event: MouseEvent) => {
    if (this.active) {
      window.scrollTo(0, 0);
    }
  };

  constructor(@Inject(PLATFORM_ID) private readonly platformId: Object,
              private readonly elementRef: ElementRef,
              private readonly ngZone: NgZone
  ) {}

  ngOnDestroy(): void {
    if (isPlatformBrowser(this.platformId)) {
      this.elementRef.nativeElement.removeEventListener('click', this.onClick, false);
    }
  }

  ngOnInit(): void {
    if (isPlatformBrowser(this.platformId)) {
      this.ngZone.runOutsideAngular(() => 
        this.elementRef.nativeElement.addEventListener('click', this.onClick, false)
      );
    }
  }
}

Uwzględnia to większość przypadków użycia, przy takim samym użyciu jak podstawowy, z tą zaletą, że włącza / wyłącza:

<a routerLink="/" linkToTop></a> <!-- always active -->
<a routerLink="/" [linkToTop]="isActive"> <!-- active when `isActive` is true -->

reklamy, nie czytaj, jeśli nie chcesz być reklamowany

Można wprowadzić kolejne ulepszenie, aby sprawdzić, czy przeglądarka obsługuje passivezdarzenia. 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 dodanym passivezdarzeniem, możesz zmienić dyrektywę na to, jeśli korzystasz z ng-event-optionsbiblioteki. Logika znajduje się wewnątrz click.pnbdetektora:

@Directive({
    selector: '[linkToTop]'
})
export class LinkToTopDirective {

    @Input()
    set linkToTop(active: string|boolean) {
        this.active = typeof active === 'string' ? active.length === 0 : active;
    }

    private active: boolean = true;

    @HostListener('click.pnb')
    onClick(): void {
      if (this.active) {
        window.scrollTo(0, 0);
      }        
    }
}

0

To działało dla mnie najlepiej dla wszystkich zmian nawigacji, w tym nawigacji skrótowej

constructor(private route: ActivatedRoute) {}

ngOnInit() {
  this._sub = this.route.fragment.subscribe((hash: string) => {
    if (hash) {
      const cmp = document.getElementById(hash);
      if (cmp) {
        cmp.scrollIntoView();
      }
    } else {
      window.scrollTo(0, 0);
    }
  });
}

0

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

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Location, PopStateEvent } from '@angular/common';
import { Router, Route, RouterLink, NavigationStart, NavigationEnd, 
    RouterEvent } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'my-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {

  private _subscription: Subscription;
  private _scrollHistory: { url: string, y: number }[] = [];
  private _useHistory = false;

  constructor(
    private _router: Router,
    private _location: Location) {
  }

  public ngOnInit() {

    this._subscription = this._router.events.subscribe((event: any) => 
    {
      if (event instanceof NavigationStart) {
        const currentUrl = (this._location.path() !== '') 
           this._location.path() : '/';
        const item = this._scrollHistory.find(x => x.url === currentUrl);
        if (item) {
          item.y = window.scrollY;
        } else {
          this._scrollHistory.push({ url: currentUrl, y: window.scrollY });
        }
        return;
      }
      if (event instanceof NavigationEnd) {
        if (this._useHistory) {
          this._useHistory = false;
          window.scrollTo(0, this._scrollHistory.find(x => x.url === 
          event.url).y);
        } else {
          window.scrollTo(0, 0);
        }
      }
    });

    this._subscription.add(this._location.subscribe((event: PopStateEvent) 
      => { this._useHistory = true;
    }));
  }

  public ngOnDestroy(): void {
    this._subscription.unsubscribe();
  }
}

0

window.scrollTo()nie działa na mnie w kątowym 5, więc użyłem document.body.scrollTopjak,

this.router.events.subscribe((evt) => {
   if (evt instanceof NavigationEnd) {
      document.body.scrollTop = 0;
   }
});

0

Jeśli ładujesz różne komponenty tą samą trasą, możesz użyć ViewportScroller, aby osiągnąć to samo.

import { ViewportScroller } from '@angular/common';

constructor(private viewportScroller: ViewportScroller) {}

this.viewportScroller.scrollToPosition([0, 0]);

0

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

import { Component, HostListener, ElementRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  isShow: boolean;
  topPosToStartShowing = 100;

  @HostListener('window:scroll')
  checkScroll() {

    const scrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;

    console.log('[scroll]', scrollPosition);

    if (scrollPosition >= this.topPosToStartShowing) {
      this.isShow = true;
    } else {
      this.isShow = false;
    }
  }

  gotoTop() {
    window.scroll({ 
      top: 0, 
      left: 10, 
      behavior: 'smooth' 
    });
  }
}

app.component.html

<style>
  p {
  font-family: Lato;
}

button {
  position: fixed;
  bottom: 5px;
  right: 5px;
  font-size: 20px;
  text-align: center;
  border-radius: 5px;
  outline: none;
}
  </style>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>

<button *ngIf="isShow" (click)="gotoTop()">👆</button>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.