Answers:
有一些解决方案,请确保将其全部检查:)
activate
每当实例化新组件时,路由器插座都会发出事件,因此我们可以使用(activate)
(例如)滚动到顶部:
app.component.html
<router-outlet (activate)="onActivate($event)" ></router-outlet>
app.component.ts
onActivate(event) {
window.scroll(0,0);
//or document.body.scrollTop = 0;
//or document.querySelector('body').scrollTo(0,0)
...
}
或使用此答案来平滑滚动
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);
}
如果希望有所选择,说不是每个组件都应触发滚动,则可以检查一下:
onActivate(e) {
if (e.constructor.name)==="login"{ // for example
window.scroll(0,0);
}
}
{ scrollPositionRestoration: 'enabled' }
在热切加载的模块上使用,它将应用于所有路由:
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
它还将进行平滑滚动。然而,这在每个路由上都存在不便。
query(':enter, :leave', style({ position: 'fixed' }), { optional: true }),
window
对象上的滚动事件在角度5中不起作用。有什么猜测吗?
如果您在Angular 6中遇到此问题,可以通过将参数添加scrollPositionRestoration: 'enabled'
到app-routing.module.ts的RouterModule中来解决此问题:
@NgModule({
imports: [RouterModule.forRoot(routes,{
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
scrollPositionRestoration
属性不适用于动态页面内容(即页面内容异步加载的地方):请参见以下Angular错误报告:github.com/angular/angular / issues / 24547
编辑:对于Angular 6+,请使用Nimesh Nishara Indimagedara的答案提及:
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled'
});
原始答案:
如果全部失败,则在模板(或父模板)上以id =“ top”在顶部(或所需的滚动到位置)创建一些空的HTML元素(例如div):
<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
选项的内置解决方案。
尽管@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;
}
});
}
}
对于6+
来自@的Angular版本,
代表用于配置路由器的选项。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]));
}
如果您使用mat-sidenav给路由器插座提供一个ID(如果您有父路由器和子路由器插座),并在其中使用激活功能,
<router-outlet id="main-content" (activate)="onActivate($event)">
然后使用此“ mat-sidenav-content”查询选择器滚动顶部
onActivate(event) {
document.querySelector("mat-sidenav-content").scrollTo(0, 0);
}
id
(router-outlet
我的应用上只有一个),效果也很好。我也以更“有角度的方式” @ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer; onActivate() { this.sidenavContainer.scrollable.scrollTo({ left: 0, top: 0 }); }
我一直在寻找一个内置的解决方案,就像AngularJS一样。但是直到那时,该解决方案才对我有用,它很简单,并且保留了后退按钮的功能。
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)
}
这是一个解决方案,仅在首次访问每个EACH组件时才会滚动到Component的顶部(以防您需要对每个组件执行不同的操作):
在每个组件中:
export class MyComponent implements OnInit {
firstLoad: boolean = true;
...
ngOnInit() {
if(this.firstLoad) {
window.scroll(0,0);
this.firstLoad = false;
}
...
}
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);
}
});
}
}
注意:预期的行为是,当您导航回到页面时,它应该向下滚动到与单击链接时相同的位置,但是在到达每个页面时都滚动到顶部。
试试这个:
app.component.ts
import {Component, OnInit, OnDestroy} from '@angular/core';
import {Router, NavigationEnd} from '@angular/router';
import {filter} from 'rxjs/operators';
import {Subscription} from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy {
subscription: Subscription;
constructor(private router: Router) {
}
ngOnInit() {
this.subscription = this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe(() => window.scrollTo(0, 0));
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
组件:订阅所有路由事件,而不是在模板中创建动作,然后在NavigationEnd b / c上滚动,否则,您将在不良导航或路线阻塞等情况下触发此操作。成功导航到一条路线,然后轻松滚动。否则,什么都不做。
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
router$: Subscription;
constructor(private router: Router) {}
ngOnInit() {
this.router$ = this.router.events.subscribe(next => this.onRouteUpdated(next));
}
ngOnDestroy() {
if (this.router$ != null) {
this.router$.unsubscribe();
}
}
private onRouteUpdated(event: any): void {
if (event instanceof NavigationEnd) {
this.smoothScrollTop();
}
}
private smoothScrollTop(): void {
const scrollToTop = window.setInterval(() => {
const pos: number = window.pageYOffset;
if (pos > 0) {
window.scrollTo(0, pos - 20); // how far to scroll on each step
} else {
window.clearInterval(scrollToTop);
}
}, 16);
}
}
的HTML
<router-outlet></router-outlet>