美文网首页
Restore Router Scroll Position

Restore Router Scroll Position

作者: forks1990 | 来源:发表于2018-11-08 13:23 被阅读0次

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);
    }
  }
}

相关文章

网友评论

      本文标题:Restore Router Scroll Position

      本文链接:https://www.haomeiwen.com/subject/rgzixqtx.html