Angular 6.1 et plus :
Angular 6.1 (publié le 2018-07-25) a ajouté un support intégré pour gérer ce problème, à travers une fonctionnalité appelée "Restauration de la position du défilement de la roulette". Comme décrit dans le document officiel Blog Angular il suffit de l'activer dans la configuration du routeur comme ceci :
RouterModule.forRoot(routes, {scrollPositionRestoration: 'enabled'})
En outre, le blog indique que "cela devrait devenir la valeur par défaut dans une prochaine version majeure". Jusqu'à présent, cela n'a pas été le cas (à partir d'Angular 11.0), mais à terme, vous n'aurez plus besoin de faire quoi que ce soit dans votre code, et cela fonctionnera correctement dès la sortie de la boîte.
Vous pouvez obtenir plus de détails sur cette fonctionnalité et sur la manière de personnaliser ce comportement dans les documents officiels .
Angular 6.0 et versions antérieures :
Bien que l'excellente réponse de @GuilhermeMeireles corrige le problème initial, 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 Location dans le code). Le comportement attendu est que lorsque vous revenez à la page, elle doit rester défilée vers le bas au même endroit que lorsque vous avez cliqué sur le lien, mais le défilement vers le haut en arrivant à chaque page brise évidemment cette attente.
Le code ci-dessous étend la logique pour détecter ce type de navigation en souscrivant à la séquence PopStateEvent de Location et en ignorant 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 naviguez est suffisamment longue pour couvrir l'ensemble du champ d'affichage, 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 retournez à 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);
}
});
}
}
52 votes
Depuis la version 6.1 d'Angular, nous pouvons utiliser { scrollPositionRestoration : 'enabled' } sur des modules chargés rapidement ou simplement dans app.module, et cette fonction sera appliquée à toutes les routes.
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
0 votes
Merci beaucoup, votre solution a parfaitement fonctionné pour moi :)
0 votes
Pas une seule personne n'a mentionné le focus ? il est plus important que jamais de prendre en charge correctement l'accessibilité / les lecteurs d'écran et si vous faites simplement défiler la page vers le haut sans tenir compte du focus, la prochaine pression sur la touche de tabulation peut sauter au bas de l'écran.
0 votes
@Manwal vous devriez mettre ceci comme réponse car c'est mieux que toutes les autres solutions.
0 votes
@MadMac Bien sûr, je l'ai ajouté comme réponse également.