Angular 2滚动到路由更改上方

在我的Angular 2应用程序中,当我向下滚动页面并单击页面底部的链接时,它确实会更改路线,并将我带到下一页,但不会滚动到页面的顶部。 因此,如果第一页冗长而第二页内容less,则给人一种第二页缺less内容的印象。 由于内容只有在用户滚动到页面顶部时才可见。

我可以将窗口滚动到组件的ngInit页面的顶部,但是,有没有更好的解决scheme,可以自动处理我的应用程序中的所有路线?

您可以在主要组件上注册路线更改侦听器,并滚动到路由更改的顶部。

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

当@ GuilhermeMeireles的优秀答案解决了原来的问题,它引入了一个新的问题,通过打破你期望的正常行为,当你回顾或前进(浏览器button或通过代码位置)。 预期的行为是当你回到页面时,它应该保持向下滚动到当你点击链接时的相同位置,但是当到达每个页面时滚动到顶部显然打破了这个期望。

下面的代码通过订阅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: '<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); } }); } } 

如果你有服务器端渲染(例如Angular Universal ),那么build议如下:

 import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router, NavigationEnd } from '@angular/router'; import { isPlatformBrowser } from '@angular/common'; import { Subscription } from 'rxjs/Rx'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit, OnDestroy { routerSubscription: Subscription; constructor(private router: Router) {} ngOnInit() { if (isPlatformBrowser) { this.routerSubscription = this.router.events .filter(event => event instanceof NavigationEnd) .subscribe(event => { window.scrollTo(0, 0); }); } } ngOnDestroy() { this.routerSubscription.unsubscribe(); } } 

注意: isPlatformBrowser检查它是否在浏览器上呈现。

您可以通过利用可观察的filter方法来更简洁地编写这些代码:

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

如果您在使用Angular Material 2 sidenav时遇到问题,将会有所帮助。 窗口或文档主体将不会有滚动条,所以您需要获取sidenav内容容器并滚动该元素,否则请尝试滚动窗口作为默认值。

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

只需点击操作即可轻松完成

在你的主要组件html中引用#scrollContainer

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

在主要组件中

 onActivate(e, scrollContainer) { scrollContainer.scrollTop = 0; } 

最好的答案在于Angular GitHub的讨论( 更改路由不会滚动到新页面顶部 )。

也许你想只在根路由器的变化(而不是在儿童,因为你可以在一个标签集加载路由延迟加载)

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

JoniJnm ( 原文 )

如果您只需要将页面滚动到顶部,就可以做到这一点(不是最好的解决scheme,但速度很快)

 document.getElementById('elementId').scrollTop = 0; 

对于iphone / ios safari,你可以用setTimeout来包装

 setTimeout(function(){ window.scrollTo(0, 1); }, 0); 

@Fernando Echeverria太棒了! 但是这个代码在散列路由器或懒惰路由器中不起作用。 因为他们不会触发位置更改。 可以试试这个:

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