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?

Naveed Ahmed
źródło
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)
        });
    }
}
Guilherme Meireles
źródło
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);
            }
        });
    }
}
Fernando Echeverria
źródło
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

Abdul Rafay
źródło
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.

mtpultz
źródło
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')
Raptor
źródło
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;
}
SAT
źródło
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'
  })],
Pran RV
źródło
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 )

zurfyx
źródło
8

Możesz dodać hak cyklu życia AfterViewInit do swojego komponentu.

ngAfterViewInit() {
   window.scrollTo(0, 0);
}
stillatmylinux
źródło
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'
  }),
  ...
]
Marty A.
źródło
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;
Aliaksei
źródło
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;
      }
    });
  }
}
Sal_Vader_808
źródło
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);
        }
      }

    });
  }

}
Simon Mathewson
źródło
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

Ifesinachi Bryan
źródło
1

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

setTimeout(function(){
    window.scrollTo(0, 1);
}, 0);
tubbsy
źródło
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;
 }`
Jonas Arguelles
źródło
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)
    }
  })
}

Witt Bulter
źródło
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);
      }        
    }
}
Poul Kruijt
źródło
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);
    }
  });
}
Jorg Janke
źródło
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();
  }
}
Vladimir Turygin
źródło
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;
   }
});
Rohan Kumar
źródło
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]);
piaszczysty
źródło
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>
wagon jogurtowy
źródło