188 votes

Angular 5 Faire défiler vers le haut à chaque clic sur la route

J'utilise angular 5. J'ai un tableau de bord où j'ai quelques sections avec un petit contenu et quelques sections avec un contenu si grand que je suis confronté à un problème lors du changement de routeur en allant vers le haut. Chaque fois que je dois faire défiler pour aller en haut. Quelqu'un peut-il m'aider à résoudre ce problème de sorte que lorsque je change de routeur, ma vue reste toujours en haut.

Merci d'avance.

1 votes

342voto

Vega Points 13451

Il existe quelques solutions, assurez-vous de les vérifier toutes :)


La prise du routeur émettra le activate à chaque fois qu'un nouveau composant est instancié, nous pourrions donc utiliser l'événement (activate) pour faire défiler (par exemple) vers le haut :

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

Utilisez, par exemple, cette solution pour un défilement en douceur :

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

Si vous souhaitez être sélectif, c'est-à-dire que tous les composants ne doivent pas déclencher le défilement, vous pouvez le vérifier dans un fichier de type if une déclaration comme celle-ci :

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

Depuis Angular6.1, nous pouvons également utiliser { scrollPositionRestoration: 'enabled' } sur les modules chargés rapidement et elle sera appliquée à toutes les routes :

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

Il fera également le défilement lisse, déjà. Cependant, cela présente l'inconvénient de le faire sur chaque itinéraire.


Une autre solution est de faire le défilement du haut sur une animation de routeur. Ajoutez ceci dans chaque transition où vous voulez faire défiler le haut :

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

2 votes

Événements de défilement sur window ne fonctionnent pas dans angular 5. Une idée de la raison ?

0 votes

@SahilBabbar, Vérifiez le corps css, overflow:hiden ? quelle est sa hauteur ?

0 votes

@Vega non. La hauteur du corps est par défaut et rien n'est codé en dur à l'intérieur, car il s'agit d'une application Angular 5 normale. De plus, jetez un coup d'oeil à la documentation d'Angular où il est dit que scroll Les événements sont mis sur liste noire par ngzones.

71voto

Si vous rencontrez ce problème dans Angular 6, vous pouvez le résoudre en ajoutant le paramètre scrollPositionRestoration: 'enabled' au RouterModule de app-routing.module.ts :

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

6 votes

Notez qu'à partir du 6 novembre 2019, en utilisant Angular 8, au moins, l'élément scrollPositionRestoration ne fonctionne pas avec le contenu dynamique des pages (c'est-à-dire lorsque le contenu de la page est chargé de manière asynchrone) : voir ce rapport de bogue Angular : github.com/angular/angular/issues/24547

46voto

GeoRover Points 151

EDITAR: Pour Angular 6+, veuillez utiliser la réponse de Nimesh Nishara Indimagedara mentionnant :

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

Réponse originale :

Si tout échoue, créez un élément HTML vide (par exemple, un div) en haut (ou à l'endroit où vous souhaitez faire défiler les pages) avec id="top" sur le modèle (ou le modèle parent) :

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

Et en composant :

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

2 votes

Cette solution a fonctionné pour moi (testé sur Chrome ainsi que sur Edge). La solution acceptée n'a pas fonctionné pour mon projet (Angular5)

0 votes

@RobvanMeeuwen, Si ma réponse n'a pas fonctionné, c'est probablement que vous ne l'avez pas implémentée de la même manière. Cette solution consiste à manipuler directement le DOM, ce qui n'est pas correct non plus.

0 votes

@Vega, c'est pourquoi j'ai appelé ça un hack. Votre solution est la bonne. Certaines personnes ici n'ont pas été en mesure de mettre en œuvre la vôtre et j'ai donc proposé un hack de secours. Ils devraient remanier leur code en fonction de la version qu'ils utilisent à ce stade.

15voto

Abdul Rafay Points 1310

Il existe désormais une solution intégrée disponible dans Angular 6.1 avec scrollPositionRestoration option.

Voir ma réponse sur Angular 2 Défilement vers le haut en cas de changement de route .

7voto

Sal_Vader_808 Points 313

Bien que @Vega fournisse la réponse directe à votre question, il y a des problèmes. Le bouton retour/avance du navigateur est cassé. Si votre utilisateur clique sur le bouton "Précédent" ou "Suivant" du navigateur, il perd sa place et se retrouve en haut de la page. Cela peut être un peu pénible pour vos utilisateurs s'ils ont dû faire défiler la page vers le bas pour atteindre un lien et qu'ils décident de cliquer en arrière pour découvrir que la barre de défilement a été remise en haut.

Voici ma solution au problème.

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 votes

Merci pour ce code avancé et cette belle solution. Mais parfois, la solution de @Vega est meilleure, car elle résout de nombreux problèmes liés à l'animation et à la hauteur dynamique des pages. Votre solution est bonne si vous avez une longue page avec du contenu et une animation de routage simple. Je l'ai essayée sur une page avec beaucoup d'animations et de blocs dynamiques et elle n'est pas très bonne. Je pense que parfois nous pouvons sacrifier la "position arrière" pour notre application. Mais sinon, votre solution est la meilleure que j'ai vue pour Angular. Merci encore

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X