Winkel 2 Scrollen Sie bei Routenänderung nach oben

296

Wenn ich in meiner Angular 2-App eine Seite nach unten scrolle und auf den Link unten auf der Seite klicke, ändert sich die Route und ich komme zur nächsten Seite, aber nicht zum oberen Rand der Seite. Wenn die erste Seite lang ist und die zweite Seite nur wenige Inhalte enthält, entsteht der Eindruck, dass der zweiten Seite der Inhalt fehlt. Da der Inhalt nur sichtbar ist, wenn der Benutzer zum Anfang der Seite blättert.

Ich kann das Fenster in ngInit der Komponente zum Anfang der Seite scrollen. Gibt es jedoch eine bessere Lösung, die alle Routen in meiner App automatisch verarbeitet?

Naveed Ahmed
quelle
20
Seit Angular 6.1 können wir {scrollPositionRestoration: 'enabled'} auf eifrig geladenen Modulen oder nur in app.module verwenden und es wird auf alle Routen angewendet. RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
Manwal
Muito obrigado sua solução funcionou perfeitamente para mim :)
Raphael Godoi
Nicht eine Person erwähnte den Fokus? Es ist wichtiger denn je, Eingabehilfen / Bildschirmleser ordnungsgemäß zu unterstützen. Wenn Sie einfach ohne Berücksichtigung des Fokus nach oben scrollen, kann der nächste Tabulatortaste zum unteren Bildschirmrand springen.
Simon_Weaver

Antworten:

386

Sie können einen Listener für Routenänderungen in Ihrer Hauptkomponente registrieren und bei Routenänderungen nach oben scrollen.

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
quelle
11
window.scrollTo(0, 0)ist eine prägnantere document.body.scrollTop = 0;und besser lesbare IMO.
Mark E. Haase
10
Hat jemand bemerkt, dass das Problem auch nach der Implementierung im Safari-Browser des Iphone weiterhin besteht? irgendwelche Gedanken?
RGK
1
@mehaase Sieht so aus, als wäre deine Antwort die beste. window.body.scrollTop funktioniert auf dem Firefox-Desktop nicht für mich. Also vielen Dank !
KCarnaille
3
Dies hat bei mir funktioniert, aber es bricht das Standardverhalten der "Zurück" -Schaltfläche. Beim Zurückgehen sollte die vorherige Bildlaufposition gespeichert werden.
JackKalish
6
Das hat funktioniert !! Obwohl ich hinzugefügt habe, $("body").animate({ scrollTop: 0 }, 1000);anstatt window.scrollTo(0, 0)das reibungslose Scrollen nach oben zu animieren
Manubhargav
360

Winkel 6.1 und höher :

Angular 6.1 (veröffentlicht am 25.07.2018) hat eine integrierte Unterstützung hinzugefügt, um dieses Problem durch eine Funktion namens "Wiederherstellung der Router-Bildlaufposition" zu beheben. Wie im offiziellen Angular-Blog beschrieben , müssen Sie dies nur in der Routerkonfiguration wie folgt aktivieren:

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

Darüber hinaus heißt es im Blog: "Es wird erwartet, dass dies in einer zukünftigen Hauptversion zum Standard wird." Bisher ist dies nicht geschehen (ab Angular 8.2), aber irgendwann müssen Sie in Ihrem Code überhaupt nichts mehr tun, und dies funktioniert sofort einwandfrei.

Weitere Details zu dieser Funktion und zum Anpassen dieses Verhaltens finden Sie in den offiziellen Dokumenten .

Winkel 6.0 und früher :

Während die hervorragende Antwort von @ GuilhermeMeireles das ursprüngliche Problem behebt, wird ein neues eingeführt, indem das normale Verhalten, das Sie beim Zurück- oder Vorwärtsnavigieren erwarten (mit Browsertasten oder über Position im Code), gebrochen wird. Das erwartete Verhalten ist, dass beim Zurücknavigieren zur Seite der Bildlauf an derselben Stelle fortgesetzt werden sollte, an der Sie auf den Link geklickt haben. Wenn Sie jedoch auf jeder Seite nach oben scrollen, wird diese Erwartung offensichtlich gebrochen.

Der folgende Code erweitert die Logik, um diese Art der Navigation zu erkennen, indem die PopStateEvent-Sequenz von Location abonniert und die Logik zum Scrollen nach oben übersprungen wird, wenn die neu erreichte Seite ein Ergebnis eines solchen Ereignisses ist.

Wenn die Seite, von der aus Sie zurück navigieren, lang genug ist, um das gesamte Ansichtsfenster abzudecken, wird die Bildlaufposition automatisch wiederhergestellt. Wenn @JordanNelson jedoch richtig darauf hingewiesen hat, müssen Sie bei einer kürzeren Seite die ursprüngliche Bildlaufposition verfolgen und wiederherstellen explizit, wenn Sie zur Seite zurückkehren. Die aktualisierte Version des Codes deckt auch diesen Fall ab, indem die Bildlaufposition immer explizit wiederhergestellt wird.

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
quelle
2
Dies sollte entweder direkt in der App-Komponente oder in einer einzelnen Komponente erfolgen (und daher von der gesamten App gemeinsam genutzt werden). Zum Beispiel habe ich es in eine Top-Navigationsleisten-Komponente aufgenommen. Sie sollten nicht in allen Ihren Komponenten enthalten sein.
Fernando Echeverria
3
Sie können dies tun, wodurch der Code besser mit anderen Plattformen kompatibel ist, die keine Browser-Plattformen sind. Einzelheiten zur Implementierung finden Sie unter stackoverflow.com/q/34177221/2858481 .
Fernando Echeverria
3
Wenn Sie in modernen Browsern auf die Schaltfläche "Zurück / Vorwärts" klicken und diese gedrückt halten, wird ein Menü angezeigt, in dem Sie zu anderen Orten als Ihrem unmittelbar vorherigen / nächsten navigieren können. Diese Lösung bricht ab, wenn Sie das tun. Für die meisten ist es ein Randfall, aber erwähnenswert.
Adamdport
1
Gibt es eine Möglichkeit, "Wiederherstellung der Router-Bildlaufposition" für verschachtelte Elemente zu aktivieren, oder funktioniert dies nur für body?
vulp
61

Ab Angular 6.1 können Sie jetzt den Ärger vermeiden und als zweiten Parameter extraOptionsan Ihren übergeben. Sie RouterModule.forRoot()können festlegen scrollPositionRestoration: enabled, dass Angular angewiesen wird, bei jeder Änderung der Route nach oben zu scrollen.

Standardmäßig finden Sie dies in 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
quelle
3
Obwohl die obige Antwort
aussagekräftiger
32

Sie können dies prägnanter schreiben, indem Sie die beobachtbare filterMethode nutzen:

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

Wenn Sie Probleme haben, bei Verwendung des Seitenavs Angular Material 2 nach oben zu scrollen, ist dies hilfreich. Das Fenster oder der Dokumentkörper verfügt nicht über die Bildlaufleiste. Sie müssen daher den sidenavInhaltscontainer abrufen und dieses Element scrollen. Andernfalls versuchen Sie standardmäßig, das Fenster zu scrollen.

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

Außerdem verfügt das Angular CDK v6.x jetzt über ein Bildlaufpaket , das bei der Handhabung des Bildlaufs hilfreich sein kann.

mtpultz
quelle
2
Großartig! Für mich hat das funktioniert -document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
Amir Tugi
Netter Kerl ... bei mtpultz & @AmirTugi. Wir beschäftigen uns jetzt damit und du hast es für mich geschafft, Prost! Wahrscheinlich wird es unvermeidlich sein, dass ich mein eigenes Navi rolle, da Material 2 nicht gut spielt, wenn die md-Symbolleiste positioniert ist: fest (oben). Es sei denn ihr habt Ideen .... ????
Tim Harker
Könnte
Tim Harker
16

Wenn Sie serverseitiges Rendern haben, sollten Sie darauf achten, den Code nicht windowsauf dem Server auszuführen, auf dem diese Variable nicht vorhanden ist. Dies würde zu einem Codebruch führen.

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();
  }
}

isPlatformBrowserist eine Funktion, mit der überprüft wird, ob die aktuelle Plattform, auf der die App gerendert wird, ein Browser ist oder nicht. Wir geben ihm die Spritze platformId.

Es ist auch möglich, die Existenz einer Variablen zu überprüfen windows, um sicher zu sein, wie folgt:

if (typeof window != 'undefined')
Raubvogel
quelle
1
Müssen Sie nicht PLATFORM_IDin die Methode injizieren constructorund diesen Wert als Parameter isPlatformBrowserangeben?
Poul Kruijt
1
@PierreDuc Ja, die Antwort ist falsch. isPlatformBrowserist eine Funktion und wird immer wahr sein. Ich habe es jetzt bearbeitet.
Lazar Ljubenović
Vielen Dank! Es ist jetzt richtig! Ich habe gerade die API überprüft: github.com/angular/angular/blob/…
Raptor
13

Machen Sie es sich einfach mit einer Klickaktion

Machen Sie in Ihrer Hauptkomponente HTML den Verweis #scrollContainer

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

in der Hauptkomponente .ts

onActivate(e, scrollContainer) {
    scrollContainer.scrollTop = 0;
}
SAT
quelle
Das zu scrollende Element befindet sich möglicherweise nicht im scrollContainerersten Knoten. Möglicherweise müssen Sie ein wenig in das Objekt graben. Für mich war es das, was wirklich funktioniert hatscrollContainer .scrollable._elementRef.nativeElement.scrollTop = 0
Byron Lopez,
13

Angular hat kürzlich eine neue Funktion eingeführt. Innerhalb des Angular-Routing-Moduls werden Änderungen wie unten vorgenommen

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

Die beste Antwort finden Sie in der Angular GitHub-Diskussion ( Ändern der Route wird auf der neuen Seite nicht nach oben gescrollt ).

Vielleicht möchten Sie nur bei Änderungen am Root-Router nach oben gehen (nicht bei untergeordneten Elementen, da Sie Routen mit verzögertem Laden in einem Tabset laden können).

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

Volle Credits an JoniJnm ( Originalbeitrag )

zurfyx
quelle
8

Sie können Ihrer Komponente den AfterViewInit- Lebenszyklus-Hook hinzufügen .

ngAfterViewInit() {
   window.scrollTo(0, 0);
}
stillatmylinux
quelle
7

Ab Angular 6.1 bietet der Router eine Konfigurationsoption namens scrollPositionRestoration, die für dieses Szenario ausgelegt ist.

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

Wenn Sie einfach die Seite nach oben scrollen müssen, können Sie dies tun (nicht die beste Lösung, aber schnell).

document.getElementById('elementId').scrollTop = 0;
Aliaksei
quelle
4

Hier ist eine Lösung, die ich mir ausgedacht habe. Ich habe die LocationStrategy mit den Router-Ereignissen gepaart. Verwenden der LocationStrategy zum Festlegen eines Booleschen Werts, um festzustellen, wann ein Benutzer gerade den Browserverlauf durchläuft. Auf diese Weise muss ich keine URL- und Y-Scroll-Daten speichern (was ohnehin nicht gut funktioniert, da alle Daten basierend auf der URL ersetzt werden). Dies löst auch den Randfall, wenn ein Benutzer die Zurück- oder Vorwärts-Taste in einem Browser gedrückt hält und mehrere Seiten anstatt nur einer Seite vorwärts oder rückwärts geht.

PS Ich habe nur die neueste Version von IE, Chrome, FireFox, Safari und Opera getestet (Stand dieses Beitrags).

Hoffe das hilft.

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
quelle
4

Diese Lösung basiert auf der Lösung von @ FernandoEcheverria und @ GuilhermeMeireles, ist jedoch präziser und funktioniert mit den Popstate-Mechanismen, die der Angular Router bietet. Dies ermöglicht das Speichern und Wiederherstellen der Bildlaufebene mehrerer aufeinanderfolgender Navigationen.

Wir speichern die Bildlaufpositionen für jeden Navigationsstatus in einer Karte scrollLevels. Sobald ein Popstate-Ereignis vorliegt, wird die ID des Status, der wiederhergestellt werden soll, vom Angular Router bereitgestellt : event.restoredState.navigationId. Dies wird dann verwendet, um die letzte Bildlaufebene dieses Status abzurufen scrollLevels.

Wenn für die Route keine gespeicherte Bildlaufebene vorhanden ist, wird wie erwartet nach oben gescrollt.

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
quelle
Genial. Ich musste eine leicht benutzerdefinierte Version erstellen, um ein Div anstelle eines Fensters zu scrollen, aber es funktionierte. Ein wesentlicher Unterschied war scrollTopvs scrollY.
BBaysinger
4

Zusätzlich zu der perfekten Antwort von @Guilherme Meireles (siehe unten) können Sie Ihre Implementierung optimieren, indem Sie einen reibungslosen Bildlauf wie unten gezeigt hinzufügen

 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)
            });
        }
    }

Fügen Sie dann das folgende Snippet hinzu

 html {
      scroll-behavior: smooth;
    }

zu Ihren styles.css

Ifesinachi Bryan
quelle
1

für iphone / ios safari kannst du mit einem setTimeout einpacken

setTimeout(function(){
    window.scrollTo(0, 1);
}, 0);
tubbsy
quelle
In meinem Fall musste auch das Seitenumbruchelement css auf gesetzt werden. height: 100vh + 1px;
Tubbsy
1

Hallo Leute, das funktioniert bei mir in Winkel 4. Sie müssen nur auf das übergeordnete Element verweisen, um beim Routerwechsel einen Bildlauf durchzuführen

layout.component.pug

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

layout.component.ts

 public routerActivate(event,outlet){
    outlet.scrollTop = 0;
 }`
Jonas Arguelles
quelle
1
Verzeihen Sie meine Faulheit, sich nicht die Mühe zu machen, Mops zu lernen, aber können Sie in HTML übersetzen?
CodyBugstein
0

@ Fernando Echeverria großartig! Dieser Code funktioniert jedoch nicht im Hash-Router oder im Lazy-Router. weil sie keine Standortänderungen auslösen. kann das versuchen:

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
quelle
0

Die Verwendung von Routerselbst führt zu Problemen, die Sie nicht vollständig überwinden können, um eine konsistente Browser-Erfahrung zu gewährleisten. Meiner Meinung nach ist die beste Methode, einfach eine benutzerdefinierte zu verwenden directiveund die Schriftrolle beim Klicken zurücksetzen zu lassen. Das Gute daran ist, dass urldie Seite auch nach oben zurückblättert , wenn Sie sich auf der gleichen Seite befinden, auf die Sie geklickt haben. Dies steht im Einklang mit normalen Websites. Das Basic directivekönnte ungefähr so ​​aussehen:

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

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

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

Mit folgender Verwendung:

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

Dies wird für die meisten Anwendungsfälle ausreichen, aber ich kann mir einige Probleme vorstellen, die sich daraus ergeben können:

  • Funktioniert nicht universalwegen der Verwendung vonwindow
  • Geringe Geschwindigkeit wirkt sich auf die Änderungserkennung aus, da sie bei jedem Klick ausgelöst wird
  • Keine Möglichkeit, diese Richtlinie zu deaktivieren

Es ist eigentlich ganz einfach, diese Probleme zu lösen:

@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)
      );
    }
  }
}

Dies berücksichtigt die meisten Anwendungsfälle mit der gleichen Verwendung wie die Basis mit dem Vorteil, dass sie aktiviert / deaktiviert werden:

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

Werbespots, lesen Sie nicht, wenn Sie nicht beworben werden möchten

Eine weitere Verbesserung könnte vorgenommen werden, um zu überprüfen, ob der Browser passiveEreignisse unterstützt oder nicht . Dies macht den Code etwas komplizierter und ist etwas unklar, wenn Sie all dies in Ihre benutzerdefinierten Anweisungen / Vorlagen implementieren möchten. Deshalb habe ich eine kleine Bibliothek geschrieben, mit der Sie diese Probleme angehen können. Um die gleiche Funktionalität wie oben und mit dem hinzugefügten passiveEreignis zu haben, können Sie Ihre Direktive in diese ändern, wenn Sie die ng-event-optionsBibliothek verwenden. Die Logik ist im click.pnbHörer:

@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
quelle
0

Dies funktionierte für mich am besten für alle Navigationsänderungen einschließlich der Hash-Navigation

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);
    }
  });
}
Jörg Janke
quelle
0

Die Hauptidee hinter diesem Code besteht darin, alle besuchten URLs zusammen mit den entsprechenden scrollY-Daten in einem Array zu speichern. Jedes Mal, wenn ein Benutzer eine Seite verlässt (NavigationStart), wird dieses Array aktualisiert. Jedes Mal, wenn ein Benutzer eine neue Seite betritt (NavigationEnd), entscheiden wir uns, die Y-Position wiederherzustellen oder nicht, je nachdem, wie wir zu dieser Seite gelangen. Wenn ein Verweis auf einer Seite verwendet wurde, scrollen wir zu 0. Wenn Browser-Vorwärts- / Rückwärtsfunktionen verwendet wurden, scrollen wir zu Y, das in unserem Array gespeichert ist. Entschuldigung für mein Englisch :)

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
quelle
0

window.scrollTo()funktioniert nicht für mich in Angular 5, also habe ich document.body.scrollTopwie verwendet,

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

Wenn Sie verschiedene Komponenten mit derselben Route laden, können Sie mit ViewportScroller dasselbe erreichen.

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

constructor(private viewportScroller: ViewportScroller) {}

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

Fenster nach oben scrollen
Sowohl window.pageYOffset als auch document.documentElement.scrollTop geben in allen Fällen das gleiche Ergebnis zurück. window.pageYOffset wird unter IE 9 nicht unterstützt.

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>
Yogesh Waghmare
quelle