我正在使用 Angular 5。我的仪表板中有几个小内容部分和几个非常大的内容部分,当我在向上导航时会遇到一个问题,需要滚动才能回到顶部。
如何解决这个问题,使得当我切换路由时,我的视图总是停留在顶部?
我正在使用 Angular 5。我的仪表板中有几个小内容部分和几个非常大的内容部分,当我在向上导航时会遇到一个问题,需要滚动才能回到顶部。
如何解决这个问题,使得当我切换路由时,我的视图总是停留在顶部?
以下是一些解决方案,请确保检查它们全部:)
选项1:
路由出口将在任何时候实例化新组件时发出activate
事件,因此我们可以使用(activate)
来滚动(例如)到顶部:
app.component.html
<router-outlet (activate)="onActivate($event)"></router-outlet>
app.component.ts
onActivate(event) {
// window.scroll(0,0);
window.scroll({
top: 0,
left: 0,
behavior: 'smooth'
});
//or document.body.scrollTop = 0;
//or document.querySelector('body').scrollTo(0,0)
...
}
由于Safari中平滑滚动的实现不太好,因此可以使用例如此解决方案来实现平滑滚动:
onActivate(event) {
let scrollToTop = window.setInterval(() => {
let pos = window.pageYOffset;
if (pos > 0) {
window.scrollTo(0, pos - 20); // how far to scroll on each step
} else {
window.clearInterval(scrollToTop);
}
}, 16);
}
如果你想要进行选择,比如不希望每个组件都触发滚动,你可以在if
语句中进行检查,例如下面这样:onActivate(e) {
if (e.constructor.name)==="login"{ // for example
window.scroll(0,0);
}
}
选项2:
自 Angular6.1 以来,我们还可以在急切加载的模块上使用 { scrollPositionRestoration: 'enabled' }
,并且它将应用于所有路由:
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
它已经可以进行平滑滚动了。但是这样做对于每次路由导航都要进行滚动来说有些不方便。
选项3:
另一种解决方案是在路由动画中进行顶部滚动。在想要滚动到顶部的每个转换中添加此内容:
query(':enter, :leave', style({ position: 'fixed' }), { optional: true })
window
对象上的滚动事件在Angular 5中无法工作。有什么猜测原因吗? - Sahil Babbar{ scrollPositionRestoration: 'enabled' }
还不是默认设置。虽然在我的懒加载模块中它起作用了。@PankajPrakash - BrunoElo如果您在Angular 6中遇到此问题,可以通过向app-routing.module.ts的RouterModule添加参数scrollPositionRestoration: 'enabled'
来解决:
@NgModule({
imports: [RouterModule.forRoot(routes,{
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
scrollPositionRestoration
属性不适用于动态页面内容(即异步加载页面内容的情况):请参见此Angular错误报告:https://github.com/angular/angular/issues/24547 - dbeachy1编辑:对于Angular 6+,请使用Nimesh Nishara Indimagedara提供的答案,它提到:
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled'
});
如果一切都失败了,那么在模板(或父模板)的顶部(或所需滚动到的位置)创建一些空的HTML元素(例如:div),并将其id设置为“top”即可。<div id="top"></div>
在组件中:
ngAfterViewInit() {
// Hack: Scrolls to top of Page after page view initialized
let top = document.getElementById('top');
if (top !== null) {
top.scrollIntoView();
top = null;
}
}
现在Angular 6.1中有一个内置的解决方案,其中包含scrollPositionRestoration
选项。
请参见我的回答,位于Angular 2 Scroll to top on Route Change上,链接此处。
对于 Angular 版本6+
来自 @docs
表示配置路由的选项。
interface ExtraOptions {
enableTracing?: boolean
useHash?: boolean
initialNavigation?: InitialNavigation
errorHandler?: ErrorHandler
preloadingStrategy?: any
onSameUrlNavigation?: 'reload' | 'ignore'
scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
anchorScrolling?: 'disabled' | 'enabled'
scrollOffset?: [number, number] | (() => [number, number])
paramsInheritanceStrategy?: 'emptyOnly' | 'always'
malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
urlUpdateStrategy?: 'deferred' | 'eager'
relativeLinkResolution?: 'legacy' | 'corrected'
}
在某些情况下,可以使用 scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
。
示例:
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled'|'top'
});
如果需要手动控制滚动,无需使用window.scroll(0,0)
,而是从 Angular V6 通用包中引入了ViewPortScoller
。
abstract class ViewportScroller {
static ngInjectableDef: defineInjectable({ providedIn: 'root', factory: () => new BrowserViewportScroller(inject(DOCUMENT), window) })
abstract setOffset(offset: [number, number] | (() => [number, number])): void
abstract getScrollPosition(): [number, number]
abstract scrollToPosition(position: [number, number]): void
abstract scrollToAnchor(anchor: string): void
abstract setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void
}
使用方法非常简单 例子:
import { Router } from '@angular/router';
import { ViewportScroller } from '@angular/common'; //import
export class RouteService {
private applicationInitialRoutes: Routes;
constructor(
private router: Router;
private viewPortScroller: ViewportScroller//inject
)
{
this.router.events.pipe(
filter(event => event instanceof NavigationEnd))
.subscribe(() => this.viewPortScroller.scrollToPosition([0, 0]));
}
虽然 @Vega 提供了直接回答您问题的方法,但存在问题。它会破坏浏览器的后退/前进按钮。如果用户点击浏览器的后退或前进按钮,他们就会失去自己的位置并被滚动到顶部。如果用户不得不向下滚动才能找到一个链接,然后决定单击后退,只发现滚动条已经被重置到顶部,这可能会给用户带来一些困扰。
以下是我解决这个问题的方法。
export class AppComponent implements OnInit {
isPopState = false;
constructor(private router: Router, private locStrat: LocationStrategy) { }
ngOnInit(): void {
this.locStrat.onPopState(() => {
this.isPopState = true;
});
this.router.events.subscribe(event => {
// Scroll to top if accessing a page, not via browser history stack
if (event instanceof NavigationEnd && !this.isPopState) {
window.scrollTo(0, 0);
this.isPopState = false;
}
// Ensures that isPopState is reset
if (event instanceof NavigationEnd) {
this.isPopState = false;
}
});
}
}
如果您正在使用mat-sidenav,请给路由器出口(如果您有父级和子级路由器出口)分配一个ID,并在其中使用activate函数。
<router-outlet id="main-content" (activate)="onActivate($event)">
并使用此“mat-sidenav-content”查询选择器滚动到顶部。
onActivate(event) {
document.querySelector("mat-sidenav-content").scrollTo(0, 0);
}
id
(我在应用程序上只有一个 router-outlet
),也能很好地工作。我还以更“Angular”的方式完成了它:@ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer;
onActivate() {
this.sidenavContainer.scrollable.scrollTo({ left: 0, top: 0 });
}
- GCSDC只需在app.module.ts
文件中添加此行:
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled' //scroll to the top
})
我正在使用Angular 11.1.4版本,它对我很有效。
window.scroll(0,0);
在ngOnInit()
中,它可以正常工作。
Angular 6.1 及以上版本:
你可以使用 Angular 6.1+ 中提供的 内置解决方案,并使用选项 scrollPositionRestoration: 'enabled'
来达到相同的效果。
@NgModule({
imports: [RouterModule.forRoot(routes,{
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
Angular 6.0及以下版本:
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);
}
});
}
}