Angular 2 Faire défiler vers le haut sur Changement d'itinéraire

296

Dans mon application Angular 2, lorsque je fais défiler une page et que je clique sur le lien en bas de la page, cela change l'itinéraire et m'amène à la page suivante, mais elle ne défile pas vers le haut de la page. Par conséquent, si la première page est longue et la 2e page a peu de contenu, cela donne l'impression que la 2e page manque de contenu. Puisque le contenu n'est visible que si l'utilisateur fait défiler vers le haut de la page.

Je peux faire défiler la fenêtre en haut de la page dans ngInit du composant mais, existe-t-il une meilleure solution qui peut gérer automatiquement tous les itinéraires dans mon application?

Naveed Ahmed
la source
20
Depuis Angular 6.1, nous pouvons utiliser {scrollPositionRestoration: 'enabled'} sur des modules chargés avec impatience ou simplement dans app.module et il sera appliqué à toutes les routes. RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
Manwal
Muito obrigado sua solução funcionou perfeitamente para mim :)
Raphael Godoi
pas une personne n'a mentionné le focus? il est plus important que jamais de prendre correctement en charge l'accessibilité / les lecteurs d'écran et si vous faites simplement défiler vers le haut sans tenir compte de la mise au point, la touche de tabulation suivante peut sauter en bas de l'écran.
Simon_Weaver

Réponses:

386

Vous pouvez enregistrer un écouteur de changement d'itinéraire sur votre composant principal et faire défiler vers le haut sur les changements d'itinéraire.

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
la source
11
window.scrollTo(0, 0)est un document.body.scrollTop = 0;OMI plus concis et plus lisible.
Mark E. Haase
10
Quelqu'un a-t-il remarqué que, même après avoir implémenté cela, le problème persiste dans le navigateur Safari d'Iphone. Des pensées?
rgk
1
@mehaase On dirait que votre réponse est la meilleure. window.body.scrollTop ne fonctionne pas pour moi sur le bureau Firefox. Alors merci !
KCarnaille
3
Cela a fonctionné pour moi, mais cela casse le comportement par défaut du bouton "retour". Revenir en arrière doit se souvenir de la position de défilement précédente.
JackKalish
6
Cela a fonctionné !! Bien que j'aie ajouté $("body").animate({ scrollTop: 0 }, 1000);plutôt que window.scrollTo(0, 0)d'animer un défilement fluide vers le haut
Manubhargav
360

Angular 6.1 et versions ultérieures :

Angular 6.1 (publié le 25/07/2018) a ajouté une prise en charge intégrée pour gérer ce problème, via une fonctionnalité appelée "Router Scroll Position Restoration". Comme décrit dans le blog officiel Angular , il vous suffit d'activer cela dans la configuration du routeur comme ceci:

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

En outre, le blog déclare "Il est prévu que cela deviendra la valeur par défaut dans une future version majeure". Jusqu'à présent, cela ne s'est pas produit (à partir d'Angular 8.2), mais vous n'aurez finalement pas besoin de faire quoi que ce soit dans votre code, et cela fonctionnera correctement hors de la boîte.

Vous pouvez voir plus de détails sur cette fonctionnalité et comment personnaliser ce comportement dans les documents officiels .

Angular 6.0 et versions antérieures :

Alors que l'excellente réponse de @ GuilhermeMeireles corrige le problème d'origine, elle en introduit un nouveau, en brisant le comportement normal que vous attendez lorsque vous naviguez en arrière ou en avant (avec les boutons du navigateur ou via Emplacement dans le code). Le comportement attendu est que lorsque vous revenez à la page, elle doit rester déroulée jusqu'au même emplacement que lorsque vous avez cliqué sur le lien, mais le défilement vers le haut en arrivant à chaque page rompt évidemment cette attente.

Le code ci-dessous développe la logique pour détecter ce type de navigation en s'abonnant à la séquence PopStateEvent de Location et en sautant la logique de défilement vers le haut si la page nouvellement arrivée est le résultat d'un tel événement.

Si la page à partir de laquelle vous revenez est suffisamment longue pour couvrir toute la fenêtre, la position de défilement est restaurée automatiquement, mais comme @JordanNelson l'a correctement souligné, si la page est plus courte, vous devez garder la trace de la position de défilement y d'origine et la restaurer. explicitement lorsque vous revenez à la page. La version mise à jour du code couvre également ce cas, en restaurant toujours explicitement la position de défilement.

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
la source
2
Cela devrait aller directement dans le composant d'application, ou dans un seul composant utilisé (et donc partagé par l'ensemble de l'application). Par exemple, je l'ai inclus dans un composant de barre de navigation supérieure. Vous ne devriez pas faire partie de tous vos composants.
Fernando Echeverria
3
Vous pouvez le faire et cela rendra le code plus largement compatible avec d'autres plates-formes autres que les navigateurs. Voir stackoverflow.com/q/34177221/2858481 pour les détails d'implémentation.
Fernando Echeverria
3
Si vous cliquez et maintenez le bouton Précédent / Suivant dans les navigateurs modernes, un menu apparaît qui vous permet de naviguer vers des emplacements autres que le précédent / suivant immédiatement. Cette solution se casse si vous faites cela. C'est un cas de pointe pour la plupart, mais mérite d'être mentionné.
adamdport
1
Existe-t-il un moyen d'activer la "restauration de la position de défilement du routeur" pour les éléments imbriqués ou cela ne fonctionne que pour body?
vulp
61

Depuis Angular 6.1, vous pouvez désormais éviter les tracas et passer extraOptionsà votre en RouterModule.forRoot()tant que deuxième paramètre et pouvez spécifier scrollPositionRestoration: enabledde dire à Angular de faire défiler vers le haut chaque fois que l'itinéraire change.

Par défaut, vous le trouverez dans 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 { }

Documents officiels angulaires

Abdul Rafay
la source
3
Même si la réponse ci-dessus est plus descriptive, j'aime que cette réponse me dise exactement où cela doit aller
ryanovas
32

Vous pouvez écrire cela plus succinctement en profitant de la filterméthode observable :

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

Si vous rencontrez des problèmes pour faire défiler vers le haut lors de l'utilisation du sidenav Angular Material 2, cela vous aidera. La fenêtre ou le corps du document n'aura pas la barre de défilement, vous devez donc obtenir le sidenavconteneur de contenu et faire défiler cet élément, sinon essayez de faire défiler la fenêtre par défaut.

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

De plus, Angular CDK v6.x a maintenant un package de défilement qui pourrait aider à gérer le défilement.

mtpultz
la source
2
Génial! Pour moi, cela a fonctionné -document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
Amir Tugi
Chers amis ... chez mtpultz & @AmirTugi. Traitant de cela en ce moment, et vous l'avez cloué pour moi, cheers! Cela finira probablement inévitablement par rouler ma propre navigation latérale, car le matériel 2 ne joue pas bien lorsque la barre d'outils md est en position: fixe (en haut). A moins que vous n'ayez des idées .... ????
Tim Harker
J'aurais peut-être trouvé ma réponse ... stackoverflow.com/a/40396105/3389046
Tim Harker
16

Si vous avez un rendu côté serveur, vous devez faire attention à ne pas exécuter le code à l'aide windowsdu serveur, où cette variable n'existe pas. Cela entraînerait une rupture de code.

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

isPlatformBrowserest une fonction utilisée pour vérifier si la plate-forme actuelle sur laquelle l'application est rendue est un navigateur ou non. On lui donne l'injectéplatformId .

Il est également possible de vérifier l'existence de variable windows, pour être sûr, comme ceci:

if (typeof window != 'undefined')
Raptor
la source
1
N'avez-vous pas besoin d'injecter PLATFORM_IDdans constructoret de donner cette valeur comme paramètre dans la isPlatformBrowserméthode de?
Poul Kruijt
1
@PierreDuc Oui, la réponse est fausse. isPlatformBrowserest une fonction et sera toujours véridique. Je l'ai édité maintenant.
Lazar Ljubenović le
Merci! C'est correct maintenant! Je viens de vérifier l'API: github.com/angular/angular/blob/…
Raptor
13

faites-le simplement avec une action de clic

dans votre composant principal html faire référence #scrollContainer

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

dans le composant principal .ts

onActivate(e, scrollContainer) {
    scrollContainer.scrollTop = 0;
}
SAM
la source
L'élément à faire défiler pourrait ne pas être dans le scrollContainerpremier nœud, vous devrez peut-être creuser un peu dans l'objet, pour moi, ce qui a vraiment fonctionnéscrollContainer .scrollable._elementRef.nativeElement.scrollTop = 0
Byron Lopez
13

Angular a récemment introduit une nouvelle fonctionnalité, à l'intérieur du module de routage angulaire, apportez des modifications comme ci-dessous

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

La meilleure réponse réside dans la discussion Angular GitHub (le changement d'itinéraire ne fait pas défiler vers le haut dans la nouvelle page ).

Peut-être que vous voulez aller en haut uniquement dans les modifications du routeur racine (pas chez les enfants, car vous pouvez charger des routes avec une charge paresseuse dans un jeu de tabulations)

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

Crédits complets à JoniJnm (article original )

zurfyx
la source
8

Vous pouvez ajouter le hook de cycle de vie AfterViewInit à votre composant.

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

Depuis Angular 6.1, le routeur fournit une option de configuration appelée scrollPositionRestoration, conçue pour répondre à ce scénario.

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

Si vous avez simplement besoin de faire défiler la page vers le haut, vous pouvez le faire (pas la meilleure solution, mais rapide)

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

Voici une solution que j'ai trouvée. J'ai jumelé la LocationStrategy avec les événements du routeur. Utilisation de LocationStrategy pour définir un booléen pour savoir quand un utilisateur traverse actuellement l'historique du navigateur. De cette façon, je n'ai pas à stocker un tas de données d'URL et de défilement y (ce qui ne fonctionne pas bien de toute façon, car chaque donnée est remplacée en fonction de l'URL). Cela résout également le cas de bord lorsqu'un utilisateur décide de maintenir le bouton Précédent ou Suivant sur un navigateur et revient en arrière ou en avant plusieurs pages plutôt qu'une seule.

PS: je n'ai testé que sur la dernière version d'IE, Chrome, FireFox, Safari et Opera (à partir de ce post).

J'espère que cela t'aides.

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
la source
4

Cette solution est basée sur la solution de @ FernandoEcheverria et @ GuilhermeMeireles, mais elle est plus concise et fonctionne avec les mécanismes popstate fournis par le routeur angulaire. Cela permet de stocker et de restaurer le niveau de défilement de plusieurs navigations consécutives.

Nous stockons les positions de défilement pour chaque état de navigation dans une carte scrollLevels. Une fois qu'il ya un événement popstate, l'ID de l'Etat qui est sur le point d'être restauré est fourni par le routeur angulaire: event.restoredState.navigationId. Il est ensuite utilisé pour obtenir le dernier niveau de défilement de cet état scrollLevels.

S'il n'y a pas de niveau de défilement enregistré pour l'itinéraire, il défilera vers le haut comme vous vous y attendez.

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
la source
Impressionnant. J'ai dû faire une version légèrement personnalisée pour faire défiler une div plutôt qu'une fenêtre, mais cela a fonctionné. Une différence essentielle était scrollTopvs scrollY.
BBaysinger
4

En plus de la réponse parfaite fournie par @Guilherme Meireles comme indiqué ci-dessous, vous pouvez modifier votre implémentation en ajoutant un défilement fluide comme indiqué ci-dessous

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

puis ajoutez l'extrait ci-dessous

 html {
      scroll-behavior: smooth;
    }

à vos styles.css

Ifesinachi Bryan
la source
1

pour iphone / ios safari, vous pouvez envelopper avec un setTimeout

setTimeout(function(){
    window.scrollTo(0, 1);
}, 0);
tubbsy
la source
dans mon cas, il fallait également définir l'élément de retour à la ligne css; height: 100vh + 1px;
tubbsy
1

Salut les gars, cela fonctionne pour moi en angulaire 4. Il vous suffit de faire référence au parent pour faire défiler le changement de routeur`

layout.component.pug

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

layout.component.ts

 public routerActivate(event,outlet){
    outlet.scrollTop = 0;
 }`
Jonas Arguelles
la source
1
pardonnez ma paresse de ne pas prendre la peine d'apprendre le pug, mais pouvez-vous traduire en HTML?
CodyBugstein
0

@Fernando Echeverria génial! mais ce code ne fonctionne pas dans le routeur de hachage ou le routeur paresseux. car ils ne déclenchent pas de changement d'emplacement. peut essayer ceci:

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
la source
0

L'utilisation de Routerlui - même entraînera des problèmes que vous ne pouvez pas résoudre complètement pour maintenir une expérience de navigateur cohérente. À mon avis, la meilleure méthode consiste à simplement utiliser une personnalisation directiveet à réinitialiser le défilement au clic. La bonne chose à ce sujet, c'est que si vous êtes sur le même urlque celui sur lequel vous cliquez, la page défilera également vers le haut. Ceci est cohérent avec les sites Web normaux. La base directivepourrait ressembler à ceci:

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

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

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

Avec l'utilisation suivante:

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

Cela suffira pour la plupart des cas d'utilisation, mais je peux imaginer quelques problèmes qui peuvent en découler:

  • Ne fonctionne pas en universalraison de l'utilisation dewindow
  • Impact à faible vitesse sur la détection des modifications, car il est déclenché à chaque clic
  • Pas moyen de désactiver cette directive

Il est en fait assez facile de surmonter ces problèmes:

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

Cela prend en compte la plupart des cas d'utilisation, avec le même usage que celui de base, avec l'avantage de l'activer / le désactiver:

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

publicités, ne lisez pas si vous ne voulez pas être annoncé

Une autre amélioration pourrait être apportée pour vérifier si le navigateur prend en charge les passiveévénements. Cela compliquera un peu plus le code et est un peu obscur si vous souhaitez implémenter tout cela dans vos directives / modèles personnalisés. C'est pourquoi j'ai écrit une petite bibliothèque que vous pouvez utiliser pour résoudre ces problèmes. Pour avoir les mêmes fonctionnalités que ci-dessus et avec l' passiveévénement ajouté , vous pouvez changer votre directive en ceci, si vous utilisez la ng-event-optionsbibliothèque. La logique est à l'intérieur de l' click.pnbauditeur:

@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
la source
0

Cela a fonctionné pour moi le mieux pour tous les changements de navigation, y compris la navigation par hachage

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
la source
0

L'idée principale derrière ce code est de conserver toutes les URL visitées avec les données scrollY respectives dans un tableau. Chaque fois qu'un utilisateur abandonne une page (NavigationStart), ce tableau est mis à jour. Chaque fois qu'un utilisateur entre dans une nouvelle page (NavigationEnd), nous décidons de restaurer la position Y ou non en fonction de la façon dont nous accédons à cette page. Si une référence sur une page a été utilisée, nous défilons à 0. Si des fonctionnalités de navigation arrière / avant du navigateur ont été utilisées, nous avons défilé jusqu'à Y enregistré dans notre tableau. Désolé pour mon anglais :)

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
la source
0

window.scrollTo()ne fonctionne pas pour moi dans Angular 5, donc j'ai utilisé document.body.scrollTopcomme,

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

Si vous chargez différents composants avec le même itinéraire, vous pouvez utiliser ViewportScroller pour obtenir la même chose.

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

constructor(private viewportScroller: ViewportScroller) {}

this.viewportScroller.scrollToPosition([0, 0]);
sablonneux
la source
0

window scroll top
window.pageYOffset et document.documentElement.scrollTop renvoient le même résultat dans tous les cas. window.pageYOffset n'est pas pris en charge sous 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>
yogesh waghmare
la source