Angular v6.1 introduce Router Scroller
which restore to scroll position before transition when browser back. It is not default enabled. Enable it is simple:
@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
}),
],
exports: [RouterModule]
})
export class AppRoutingModule {}
It may not work as you expected, if your component dynamic load data on shown. Router Scroller
try to restore last position, but content not loaded yet.
Here is the steps to solve:
Disable Auto Scroll
@NgModule({
imports: [
RouterModule.forRoot(routes, {
// it will be enabled by default in future version
scrollPositionRestoration: 'disable',
}),
],
exports: [RouterModule]
})
export class AppRoutingModule {}
Create Service to do Manual Scroll
import { ViewportScroller } from '@angular/common';
import { Injectable } from '@angular/core';
import { Router, Scroll } from '@angular/router';
import { filter, throttleTime } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class RouterScrollService {
constructor(router: Router, private viewportScroller: ViewportScroller) {
router.events.pipe(filter(e => e instanceof Scroll), throttleTime(200))
.subscribe((e: Scroll) => {
const pos = e.position || [0, 0];
viewportScroller.scrollToPosition(pos);
});
}
}
Router may trigger multiple Scroll event during one router navigation, use throttleTime
rxjs filter out later scroll events. Not use debounceTime
, its delay cause UI slug.
Scroll to Correct Position after Component Finished Load
Add componentLoaded()
to notify RouterScrollService
that component finished loading, try scroll again, this time is likely to scroll correct position.
import { ViewportScroller } from '@angular/common';
import { Injectable } from '@angular/core';
import { Router, Scroll } from '@angular/router';
import { filter, throttleTime } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class RouterScrollService {
private lastPosition: [number, number] = [0, 0];
private lastScrollTime = 0;
constructor(router: Router, private viewportScroller: ViewportScroller) {
router.events.pipe(filter(e => e instanceof Scroll), throttleTime(200))
.subscribe((e: Scroll) => {
const pos = e.position || [0, 0];
this.lastPosition = pos;
this.lastScrollTime = Date.now();
viewportScroller.scrollToPosition(pos);
});
}
async componentLoaded() {
const d = Date.now();
if (d - this.lastScrollTime < 1000) {
this.lastScrollTime = d;
// wait for browser complete re-layout
await Promise.resolve();
this.viewportScroller.scrollToPosition(this.lastPosition);
}
}
}
网友评论