在我的Angular 2应用中,当我向下滚动页面并单击页面底部的链接时,它确实会改变路由并将我带到下一页,但它不会滚动到页面顶部。因此,如果第一页很长,第二页内容很少,就会给人一种第二页缺乏内容的印象。因为只有当用户滚动到页面顶部时,内容才可见。
我可以滚动窗口到ngInit组件的页面顶部,但是,有没有更好的解决方案,可以自动处理我的应用程序中的所有路由?
在我的Angular 2应用中,当我向下滚动页面并单击页面底部的链接时,它确实会改变路由并将我带到下一页,但它不会滚动到页面顶部。因此,如果第一页很长,第二页内容很少,就会给人一种第二页缺乏内容的印象。因为只有当用户滚动到页面顶部时,内容才可见。
我可以滚动窗口到ngInit组件的页面顶部,但是,有没有更好的解决方案,可以自动处理我的应用程序中的所有路由?
当前回答
如果你只是需要滚动页面到顶部,你可以这样做(不是最好的解决方案,但很快)
document.getElementById('elementId').scrollTop = 0;
其他回答
只需点击动作就可以轻松完成
在你的主组件html引用#scrollContainer
<div class="main-container" #scrollContainer>
<router-outlet (activate)="onActivate($event, scrollContainer)"></router-outlet>
</div>
在主组件.ts中
onActivate(e, scrollContainer) {
scrollContainer.scrollTop = 0;
}
这个解决方案基于@FernandoEcheverria和@GuilhermeMeireles的解决方案,但它更简洁,并且可以使用Angular路由器提供的popstate机制。这允许存储和恢复多个连续导航的滚动级别。
我们将每个导航状态的滚动位置存储在一个地图scrollLevels中。一旦有了popstate事件,即将被恢复的状态ID就会由Angular路由器提供:event. restoredstate . navigationid。然后,这将用于从scrollLevels获取该状态的最后一个滚动级别。
如果路由没有存储滚动级别,它将滚动到顶部,正如您所期望的那样。
import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
@Component({
selector: 'my-app',
template: '<ng-content></ng-content>',
})
export class AppComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit() {
const scrollLevels: { [navigationId: number]: number } = {};
let lastId = 0;
let restoredId: number;
this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationStart) {
scrollLevels[lastId] = window.scrollY;
lastId = event.id;
restoredId = event.restoredState ? event.restoredState.navigationId : undefined;
}
if (event instanceof NavigationEnd) {
if (restoredId) {
// Optional: Wrap a timeout around the next line to wait for
// the component to finish loading
window.scrollTo(0, scrollLevels[restoredId] || 0);
} else {
window.scrollTo(0, 0);
}
}
});
}
}
对于每个正在寻找解决方案并阅读这篇文章的人。的
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled'
}),
...
]
并没有回答这个主题的问题。如果我们查看Angular的源代码,我们会看到一些有趣的行:
这个东西只对反向导航有用。其中一个解决方案可能是:
constructor(router: Router) {
router.events
.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd))
.subscribe(() => {
this.document.querySelector('#top').scrollIntoView();
});
}
这将查看每个导航到该id的div并滚动到它;
另一种方法是使用相同的逻辑,但在decorator或指令的帮助下,允许你选择何时何地滚动顶部;
这对我来说最适合所有导航更改,包括哈希导航
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this._sub = this.route.fragment.subscribe((hash: string) => {
if (hash) {
const cmp = document.getElementById(hash);
if (cmp) {
cmp.scrollIntoView();
}
} else {
window.scrollTo(0, 0);
}
});
}
这段代码背后的主要思想是将所有访问过的url和各自的scrollY数据保存在一个数组中。每当用户放弃一个页面(NavigationStart),这个数组就会被更新。每当用户进入一个新页面(NavigationEnd)时,我们决定是否恢复Y位置,这取决于我们如何到达这个页面。如果使用了某个页面上的引用,则滚动到0。如果使用浏览器后退/前进特性,则滚动到保存在数组中的Y。对不起,我的英语不好:)
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Location, PopStateEvent } from '@angular/common';
import { Router, Route, RouterLink, NavigationStart, NavigationEnd,
RouterEvent } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'my-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
private _subscription: Subscription;
private _scrollHistory: { url: string, y: number }[] = [];
private _useHistory = false;
constructor(
private _router: Router,
private _location: Location) {
}
public ngOnInit() {
this._subscription = this._router.events.subscribe((event: any) =>
{
if (event instanceof NavigationStart) {
const currentUrl = (this._location.path() !== '')
this._location.path() : '/';
const item = this._scrollHistory.find(x => x.url === currentUrl);
if (item) {
item.y = window.scrollY;
} else {
this._scrollHistory.push({ url: currentUrl, y: window.scrollY });
}
return;
}
if (event instanceof NavigationEnd) {
if (this._useHistory) {
this._useHistory = false;
window.scrollTo(0, this._scrollHistory.find(x => x.url ===
event.url).y);
} else {
window.scrollTo(0, 0);
}
}
});
this._subscription.add(this._location.subscribe((event: PopStateEvent)
=> { this._useHistory = true;
}));
}
public ngOnDestroy(): void {
this._subscription.unsubscribe();
}
}