我的 Angular 8 应用程序在导航到新页面时滚动到顶部。在一个特定页面上我有一个可排序的表格。导航到该页面时,它应该滚动到顶部,但是当单击表头单元格时,它应该使用排序更新查询参数,但不滚动到顶部。
是否可以使用新的查询参数数据调用
router.navigate(...)
而不触发滚动到顶部,同时不禁用从路线本身滚动到顶部?
您可以使用多个选项配置路由器模块。您应该能够使用 scrollPositionRestoration 选项保留滚动。
您可以像这样使用它:
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'disabled' })
话虽如此,此选项将保留所有页面的滚动位置。
如果您只想针对特定页面实现此目的,则可以选择在 navigate
调用中使用
navigationExtras并在 state 对象中指定当前滚动位置,并在
AfterViewInit
处理程序更新滚动位置时。
假设您有一个包含表的容器,您可以使用
ViewChild
装饰器在组件文件中访问它。
// declare your container component
@ViewChild("container")
private container: ElementRef;
// after view init updated current scroll position
ngAfterViewInit() {
const prevScrollPos = this.router.getCurrentNavigation()?.extras?.state?.scrollTop;
if (prevScrollPos) {
this.container.nativeElement.scrollTop = prevScrollPos;
}
}
// specify scroll position on navigation
this.router.navigate(
['/login'],
{
state: { scrollTop: this.container.nativeElement.scrollTop }
}
);
由于导航()方法返回一个承诺,一旦承诺解决,您就可以滚动到特定位置:
let currentScrollHeight = window.pageYOffset
this.router.navigate(['my-page']).then(() => window.scrollTo({ top: currentScrollHeight }))
或者,如果你像我一样使用 rxjs,你可以将 Promise 转换为 observable 并执行相同的操作:
let currentScrollHeight = window.pageYOffset
from(this.router.navigate(['my-page'])).pipe(
first(),
tap(() => window.scrollTo({ top: currentScrollHeight }))
).subscribe()
此方法不会在我的机器上产生任何闪烁/跳跃,这正是我所希望的。
单击锚点时,将
@Viewchild
与 block:'nearest'
结合使用,以防止页面跳转到顶部:
@ViewChild("el") private el: ElementRef;
this.el.nativeElement.scrollIntoView({ behavior: "smooth", block:'nearest' });
我最近遇到了同样的问题,并想出了一个新颖的解决方案。 它仍然很老套,但至少它是相当封闭的,不需要特殊的配置或逻辑分布在应用程序的多个部分。
Angular 的路由器使用 window.scrollTo 方法滚动回顶部,为什么不暂时禁用该方法并在导航后重新启用它:
export class MyComponent {
static readonly windowScrollToBackup = window.scrollTo;
navigateWithoutScrollToTop(url: UrlTree) {
window.scrollTo = () => {};
this.router.navigateByUrl(url).then(() => {
setTimeout(() => {
window.scrollTo = MyComponent.windowScrollToBackup;
}, 0);
});
}
}