Winkel 5 Scrollen Sie bei jedem Routenklick nach oben


99

Ich verwende Angular 5. Ich habe ein Dashboard, in dem ich nur wenige Abschnitte mit kleinem Inhalt und wenige Abschnitte mit so großem Inhalt habe, dass ich beim Wechseln des Routers nach oben auf ein Problem stoße. Jedes Mal muss ich scrollen, um nach oben zu gelangen. Kann mir jemand helfen, dieses Problem zu lösen, damit meine Ansicht beim Wechseln des Routers immer oben bleibt.

Danke im Voraus.


Mögliches Duplikat von Angular 2
Scrollen Sie

Antworten:


209

Es gibt einige Lösungen, stellen Sie sicher, dass Sie alle überprüfen :)

Der Router-Ausgang gibt das activateEreignis jedes Mal aus, wenn eine neue Komponente instanziiert wird, sodass wir (activate)(zum Beispiel) nach oben scrollen können:

app.component.html

<router-outlet (activate)="onActivate($event)" ></router-outlet>

app.component.ts

onActivate(event) {
    window.scroll(0,0);
    //or document.body.scrollTop = 0;
    //or document.querySelector('body').scrollTo(0,0)
    ...
}

oder verwenden Sie diese Antwort , um das Scrollen zu glätten

    onActivate(event) {
        let scrollToTop = window.setInterval(() => {
            let pos = window.pageYOffset;
            if (pos > 0) {
                window.scrollTo(0, pos - 20); // how far to scroll on each step
            } else {
                window.clearInterval(scrollToTop);
            }
        }, 16);
    }

Wenn Sie selektiv sein möchten, sagen Sie, dass nicht jede Komponente das Scrollen auslösen soll. Sie können dies überprüfen:

onActivate(e) {
    if (e.constructor.name)==="login"{ // for example
            window.scroll(0,0);
    }
}


Seit Angular6.1 können wir es auch { scrollPositionRestoration: 'enabled' }auf eifrig geladenen Modulen verwenden und es wird auf alle Routen angewendet:

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

Es wird auch das reibungslose Scrollen ausführen. Dies ist jedoch für jedes Routing unpraktisch.


Eine andere Lösung besteht darin, die Router-Animation nach oben zu scrollen. Fügen Sie dies in jedem Übergang hinzu, in dem Sie nach oben scrollen möchten:

query(':enter, :leave', style({ position: 'fixed' }), { optional: true }),

4
es funktioniert . Danke für deine Antwort. Sie sparen viel Zeit für mich
Raihan

2
Bildlaufereignisse auf dem windowObjekt funktionieren nicht in Winkel 5. Irgendwelche Vermutungen warum?
Sahil Babbar

2
Ein echter Held hier. Ersparte mögliche Stunden der Frustration. Danke dir!
Anjana Silva

1
@AnjanaSilva, danke für den positiven Kommentar! Ich bin sehr froh, dass es Ihnen helfen konnte :)
Vega

2
Gibt es eine Möglichkeit für ein Lazyloaded-Modul?
Pankaj Prakash

52

Wenn dieses Problem in Angular 6 scrollPositionRestoration: 'enabled'auftritt , können Sie es beheben, indem Sie den Parameter zu RouterModule von app-routing.module.ts hinzufügen:

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

7
Bitte posten Sie keine Bilder von Code. Kopieren Sie einfach den Code selbst und fügen Sie ihn direkt in Ihre Antwort ein.
Mypetlion

2
Sicher. Nächstes mal werde ich. Ich bin nur ein bisschen neu hier. :)
Nimezzz

4
Beachten Sie, dass die scrollPositionRestorationEigenschaft ab dem 6. November 2019 mit Angular 8 zumindest nicht mit dynamischem Seiteninhalt funktioniert (dh wenn der Seiteninhalt asynchron geladen wird): Weitere Informationen finden
dbeachy1

25

BEARBEITEN: Für Angular 6+ verwenden Sie bitte die Antwort von Nimesh Nishara Indimagedara und erwähnen Sie:

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

Ursprüngliche Antwort:

Wenn alles fehlschlägt, erstellen Sie oben ein leeres HTML-Element (z. B. div) (oder einen gewünschten Bildlauf zum Speicherort) mit der ID = "top" in der Vorlage (oder der übergeordneten Vorlage):

<div id="top"></div>

Und in Komponente:

  ngAfterViewInit() {
    // Hack: Scrolls to top of Page after page view initialized
    let top = document.getElementById('top');
    if (top !== null) {
      top.scrollIntoView();
      top = null;
    }
  }

2
Diese Lösung hat bei mir funktioniert (sowohl auf Chrome als auch auf Edge getestet). Die akzeptierte Lösung funktionierte nicht für mein Projekt (Angular5)
Rob van Meeuwen

@RobvanMeeuwen, Wenn meine Antwort nicht funktioniert hat, haben Sie sie wahrscheinlich nicht auf die gleiche Weise implementiert. Diese Lösung manipuliert direkt das DOM, das auch nicht sicher korrekt ist
Vega

@Vega, deshalb habe ich es einen Hack genannt. Ihre Lösung ist die richtige. Einige Leute hier konnten Ihre nicht implementieren, deshalb habe ich den Fallback-Hack angeboten. Sie sollten ihren Code basierend auf der Version, in der sie sich zu diesem Zeitpunkt befinden, umgestalten.
GeoRover

Von all dieser Lösung ist Arbeit für mich. Vielen Dank @GeoRover
Gangani Roshan

Verwenden Sie für Angular 6+ die Antwort von Nimesh Nishara Indimagedara.
GeoRover


6

Obwohl @Vega die direkte Antwort auf Ihre Frage bietet, gibt es Probleme. Dadurch wird die Vor- / Zurück-Schaltfläche des Browsers unterbrochen. Wenn Ihr Benutzer auf die Schaltfläche "Zurück" oder "Vorwärts" des Browsers klickt, verliert er seinen Platz und wird ganz oben gescrollt. Dies kann für Ihre Benutzer etwas schmerzhaft sein, wenn sie nach unten scrollen mussten, um zu einem Link zu gelangen, und sich entschieden haben, nur zurück zu klicken, um festzustellen, dass die Bildlaufleiste nach oben zurückgesetzt wurde.

Hier ist meine Lösung für das Problem.

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

2
Vielen Dank für den erweiterten Code und die nette Lösung. Aber manchmal ist die @ Mega-Lösung besser, weil sie viele Probleme mit Animation und dynamischer Seitenhöhe löst. Ihre Lösung ist gut, wenn Sie eine lange Seite mit Inhalten und einer einfachen Routing-Animation haben. Ich versuche es auf einer Seite mit vielen Animations- und Dynamikblöcken und es sieht nicht so gut aus. Ich denke, manchmal können wir die "Rückenposition" für unsere App opfern. Aber wenn nicht - Ihre Lösung ist die beste, die ich für Angular sehe.
Nochmals vielen

5

In meinem Fall habe ich gerade hinzugefügt

window.scroll(0,0);

in ngOnInit()und es funktioniert gut.


4

Ab Angular Version 6+ Keine Verwendung von window.scroll (0,0)

Für Angular-Version 6+von @ Stellt Optionen zum Konfigurieren des Routers dar.docs

interface ExtraOptions {
  enableTracing?: boolean
  useHash?: boolean
  initialNavigation?: InitialNavigation
  errorHandler?: ErrorHandler
  preloadingStrategy?: any
  onSameUrlNavigation?: 'reload' | 'ignore'
  scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
  anchorScrolling?: 'disabled' | 'enabled'
  scrollOffset?: [number, number] | (() => [number, number])
  paramsInheritanceStrategy?: 'emptyOnly' | 'always'
  malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
  urlUpdateStrategy?: 'deferred' | 'eager'
  relativeLinkResolution?: 'legacy' | 'corrected'
}

Man kann scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'in verwenden

Beispiel:

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

Und wenn man das Scrollen manuell steuern muss, wurde kein window.scroll(0,0) gemeinsames Paket von Angular V6 eingeführt ViewPortScoller.

abstract class ViewportScroller {
  static ngInjectableDef: defineInjectable({ providedIn: 'root', factory: () => new BrowserViewportScroller(inject(DOCUMENT), window) })
  abstract setOffset(offset: [number, number] | (() => [number, number])): void
  abstract getScrollPosition(): [number, number]
  abstract scrollToPosition(position: [number, number]): void
  abstract scrollToAnchor(anchor: string): void
  abstract setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void
}

Die Verwendung ist ziemlich einfach. Beispiel:

import { Router } from '@angular/router';
import {  ViewportScroller } from '@angular/common'; //import
export class RouteService {

  private applicationInitialRoutes: Routes;
  constructor(
    private router: Router;
    private viewPortScroller: ViewportScroller//inject
  )
  {
   this.router.events.pipe(
            filter(event => event instanceof NavigationEnd))
            .subscribe(() => this.viewPortScroller.scrollToPosition([0, 0]));
}

4

Wenn Sie mat-sidenav verwenden, geben Sie dem Router-Ausgang eine ID (wenn Sie einen übergeordneten und einen untergeordneten Router-Ausgang haben), verwenden Sie die Aktivierungsfunktion <router-outlet id="main-content" (activate)="onActivate($event)"> und verwenden Sie diese Abfrageauswahl "mat-sidenav-content", um nach oben zu scrollen onActivate(event) { document.querySelector("mat-sidenav-content").scrollTo(0, 0); }


Funktioniert auch ohne Verwendung von id (ich habe eine Single router-outletin meiner App). Ich habe es auch auf einem "eckigeren Weg" gemacht: @ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer; onActivate() { this.sidenavContainer.scrollable.scrollTo({ left: 0, top: 0 }); }
GCSDC

3

Ich bin immer auf der Suche nach einer integrierten Lösung für dieses Problem, wie es sie in AngularJS gibt. Aber bis dahin funktioniert diese Lösung für mich. Sie ist einfach und bewahrt die Funktionalität der Zurück-Schaltfläche.

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

Antwort von zurfyx Originalbeitrag


3

Sie müssen nur eine Funktion erstellen, die die Anpassung des Bildlaufs Ihres Bildschirms enthält

beispielsweise

window.scroll(0,0) OR window.scrollTo() by passing appropriate parameter.

window.scrollTo (xpos, ypos) -> erwarteter Parameter.


2

Hier ist eine Lösung, die nur beim ersten Besuch für JEDE Komponente zum Anfang der Komponente scrollt (falls Sie pro Komponente etwas anderes tun müssen):

In jeder Komponente:

export class MyComponent implements OnInit {

firstLoad: boolean = true;

...

ngOnInit() {

  if(this.firstLoad) {
    window.scroll(0,0);
    this.firstLoad = false;
  }
  ...
}

2

export class AppComponent {
  constructor(private router: Router) {
    router.events.subscribe((val) => {
      if (val instanceof NavigationEnd) {
        window.scrollTo(0, 0);
      }
    });
  }

}


2

Winkel 6.1 und höher:

Sie können Gebrauch in Lösung gebaut in verfügbar Angular 6.1+ mit der Option , scrollPositionRestoration: 'enabled'das gleiche zu erreichen.

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

Winkel 6.0 und früher:

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

Hinweis: Das erwartete Verhalten besteht darin, dass beim Zurücknavigieren zur Seite ein Bildlauf an derselben Stelle durchgeführt werden sollte, an der Sie auf den Link geklickt haben, aber bei jedem Aufrufen jeder Seite nach oben gescrollt werden sollte.



2

Für jemanden, der nach einer Bildlauffunktion sucht, fügen Sie einfach die Funktion hinzu und rufen Sie bei Bedarf auf

scrollbarTop(){

  window.scroll(0,0);
}

1

Versuche dies:

app.component.ts

import {Component, OnInit, OnDestroy} from '@angular/core';
import {Router, NavigationEnd} from '@angular/router';
import {filter} from 'rxjs/operators';
import {Subscription} from 'rxjs';

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

    constructor(private router: Router) {
    }

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

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

1

Komponente: Abonnieren Sie alle Routing-Ereignisse, anstatt eine Aktion in der Vorlage zu erstellen, und scrollen Sie zu NavigationEnd b / c. Andernfalls wird dies bei fehlerhaften Navigationsgeräten oder blockierten Routen usw. ausgelöst. Dies ist ein sicherer Weg, um festzustellen, ob Eine Route wird erfolgreich navigiert und anschließend gescrollt. Ansonsten nichts tun.

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

  router$: Subscription;

  constructor(private router: Router) {}

  ngOnInit() {
    this.router$ = this.router.events.subscribe(next => this.onRouteUpdated(next));
  }

  ngOnDestroy() {
    if (this.router$ != null) {
      this.router$.unsubscribe();
    }
  }

  private onRouteUpdated(event: any): void {
    if (event instanceof NavigationEnd) {
      this.smoothScrollTop();
    }
  }

  private smoothScrollTop(): void {
    const scrollToTop = window.setInterval(() => {
      const pos: number = window.pageYOffset;
      if (pos > 0) {
          window.scrollTo(0, pos - 20); // how far to scroll on each step
      } else {
          window.clearInterval(scrollToTop);
      }
    }, 16);
  }

}

HTML

<router-outlet></router-outlet>

1

Versuche dies

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

Dieser Code unterstützt Winkel 6 <=

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.