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?
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
Réponses:
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.
la source
window.scrollTo(0, 0)
est undocument.body.scrollTop = 0;
OMI plus concis et plus lisible.$("body").animate({ scrollTop: 0 }, 1000);
plutôt quewindow.scrollTo(0, 0)
d'animer un défilement fluide vers le hautAngular 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:
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.
la source
body
?Depuis Angular 6.1, vous pouvez désormais éviter les tracas et passer
extraOptions
à votre enRouterModule.forRoot()
tant que deuxième paramètre et pouvez spécifierscrollPositionRestoration: enabled
de 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
:Documents officiels angulaires
la source
Vous pouvez écrire cela plus succinctement en profitant de la
filter
méthode observable :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
sidenav
conteneur de contenu et faire défiler cet élément, sinon essayez de faire défiler la fenêtre par défaut.De plus, Angular CDK v6.x a maintenant un package de défilement qui pourrait aider à gérer le défilement.
la source
document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
Si vous avez un rendu côté serveur, vous devez faire attention à ne pas exécuter le code à l'aide
windows
du serveur, où cette variable n'existe pas. Cela entraînerait une rupture de code.isPlatformBrowser
est 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:la source
PLATFORM_ID
dansconstructor
et de donner cette valeur comme paramètre dans laisPlatformBrowser
méthode de?isPlatformBrowser
est une fonction et sera toujours véridique. Je l'ai édité maintenant.faites-le simplement avec une action de clic
dans votre composant principal html faire référence #scrollContainer
dans le composant principal .ts
la source
scrollContainer
premier 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
Angular a récemment introduit une nouvelle fonctionnalité, à l'intérieur du module de routage angulaire, apportez des modifications comme ci-dessous
la source
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 ).
app.component.html
app.component.ts
Crédits complets à JoniJnm (article original )
la source
Vous pouvez ajouter le hook de cycle de vie AfterViewInit à votre composant.
la source
Depuis Angular 6.1, le routeur fournit une option de configuration appelée
scrollPositionRestoration
, conçue pour répondre à ce scénario.la source
Si vous avez simplement besoin de faire défiler la page vers le haut, vous pouvez le faire (pas la meilleure solution, mais rapide)
la source
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.
la source
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 étatscrollLevels
.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.
la source
scrollTop
vsscrollY
.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
puis ajoutez l'extrait ci-dessous
à vos styles.css
la source
pour iphone / ios safari, vous pouvez envelopper avec un setTimeout
la source
height: 100vh + 1px;
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
layout.component.ts
la source
@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:
la source
L'utilisation de
Router
lui - 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 personnalisationdirective
et à réinitialiser le défilement au clic. La bonne chose à ce sujet, c'est que si vous êtes sur le mêmeurl
que celui sur lequel vous cliquez, la page défilera également vers le haut. Ceci est cohérent avec les sites Web normaux. La basedirective
pourrait ressembler à ceci:Avec l'utilisation suivante:
Cela suffira pour la plupart des cas d'utilisation, mais je peux imaginer quelques problèmes qui peuvent en découler:
universal
raison de l'utilisation dewindow
Il est en fait assez facile de surmonter ces problèmes:
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:
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 lang-event-options
bibliothèque. La logique est à l'intérieur de l'click.pnb
auditeur:la source
Cela a fonctionné pour moi le mieux pour tous les changements de navigation, y compris la navigation par hachage
la source
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 :)
la source
window.scrollTo()
ne fonctionne pas pour moi dans Angular 5, donc j'ai utilisédocument.body.scrollTop
comme,la source
Si vous chargez différents composants avec le même itinéraire, vous pouvez utiliser ViewportScroller pour obtenir la même chose.
la source
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
app.component.html
la source