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.

Raihan
quelle
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 }),
Vega
quelle
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]
})
Nimezzz
quelle
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;
    }
  }
GeoRover
quelle
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;
      }
    });
  }
}
Sal_Vader_808
quelle
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.

Zohab Ali
quelle
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]));
}
Vikas
quelle
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); }

ivin antony
quelle
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

Jared Whipple
quelle
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.

Vijay Barot
quelle
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;
  }
  ...
}
0_tr0jan_0
quelle
2

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

}

Irhetorik
quelle
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.

s sharif
quelle
2

einfach hinzufügen

window.scrollTo({ top: 0);

zu ngOnInit ()

Max Hesari
quelle
window.scroll (0,0)
Akitha_MJ
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);
}
Akitha_MJ
quelle
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();
    }
}
Eray T.
quelle
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>
Joshua Michael Waggoner
quelle
1

Versuche dies

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

Dieser Code unterstützt Winkel 6 <=

Rokive
quelle