在路由更改时将 Angular 2 滚动到顶部
在路由更改时将 Angular 2 滚动到顶部
在我的Angular 2应用中,当我向下滚动页面并点击页面底部的链接时,虽然路由会改变并带我到下一页,但它不会滚动到页面顶部。因此,如果第一页很长,而第二页内容很少,就会给人一种第二页内容不足的印象。因为内容只有当用户滚动到页面顶部时才能看到。
我可以在组件的ngInit中将窗口滚动到页面顶部,但是有没有更好的解决方案,可以自动处理我的应用中的所有路由呢?
\n\n你可以在你的主组件上注册一个路由变化监听器,在路由变化时滚动到顶部。 \n\n
import { Component, OnInit } from '@angular/core'; import { Router, NavigationEnd } from '@angular/router'; @Component({ selector: 'my-app', template: '', }) export class MyAppComponent implements OnInit { constructor(private router: Router) { } ngOnInit() { this.router.events.subscribe((evt) => { if (!(evt instanceof NavigationEnd)) { return; } window.scrollTo(0, 0) }); } }
Angular 6.1及以后版本:
Angular 6.1(发布于2018年7月25日)添加了内置支持,通过名为“路由器滚动位置恢复”的特性来处理此问题。正如官方Angular博客所述,您只需要像这样在路由器配置中启用即可:
RouterModule.forRoot(routes, {scrollPositionRestoration: 'enabled'})
此外,博客中指出:“预计在未来的重大版本发布中,这将成为默认设置。”目前尚未发生(截至Angular 11.0),但最终您无需在代码中进行任何操作,这将以正确的方式正确地工作。
您可以在官方文档中了解更多有关此功能以及如何自定义此行为的详细信息。
Angular 6.0及更早版本:
虽然@GuilhermeMeireles的优秀答案解决了原始问题,但它引入了一个新问题,即破坏了您在向前或向后导航时期望的正常行为(使用浏览器按钮或通过代码中的Location)。期望的行为是当您返回到页面时,它应该保持滚动到您单击链接时的相同位置,而在到达每个页面时滚动到顶部显然破坏了这种期望。
以下代码扩展了检测此类导航的逻辑,通过订阅Location的PopStateEvent序列并在新到达的页面是此类事件的结果时跳过滚动到顶部的逻辑。
如果您从导航回退的页面足够长以覆盖整个视口,则滚动位置会自动恢复,但正如 @JordanNelson 正确指出的那样,如果页面较短,则需要跟踪原始的y滚动位置,并在返回页面时显式恢复它。代码的更新版本也处理了这种情况,始终显式恢复滚动位置。
import { Component, OnInit } from '@angular/core'; import { Router, NavigationStart, NavigationEnd } from '@angular/router'; import { Location, PopStateEvent } from "@angular/common"; @Component({ selector: 'my-app', template: '', }) 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); } }); } }