Угловой 6 - сохранить положение прокрутки при изменении маршрута

Предыдущее поведение:

Изменение маршрута или пути навигации не повлияет на положение прокрутки при переходе на другой маршрут. Т.е. содержимое может меняться без изменения положения прокрутки.

Текущее поведение:

Изменение маршрута вернет вас обратно в начало страницы.

Действие сделано до сих пор:

Проверено на текущем и новом новом проекте Angular 6

Это ошибка? изменить функцию? или есть параметр, который я пропускаю.

6 ответов

Решение

Похоже, установка scrollPositionRestoration на отключенный исправляет это

RouterModule.forRoot(
  appRoutes,
  { scrollPositionRestoration: 'disabled' } // <-- HERE
)

Смотрите https://angular.io/api/router/ExtraOptions

Положение прокрутки не изменится после изменения маршрута. Это всегда поведение по умолчанию для Angular.

Тем не менее, многие разработчики вручную делают window.scroll(0, 0) переписать это поведение.

Я бы посоветовал вам проверить, если что-то в вашем коде делает это. Потому что это может быть недавно установленная сторонняя библиотека или другой код разработчика.

Также, согласно следующей официальной статье:

Angular v6.1 теперь доступен - TypeScript 2.9, позиционирование прокрутки и многое другое

Существует новая опция, чтобы сохранить исходную позицию прокрутки с помощью

RouterModule.forRoot(routes, {scrollPositionRestoration: 'enabled'})

Я считаю, что это не имеет прямого отношения к вопросу, который вы задаете, а просто к чему-то хорошему.

Этот ответ предназначен для тех, кто пришел сюда, потому что они хотят, чтобы позиция прокрутки не менялась, когда навигация по маршруту используется для обновления параметров запроса следующим образом:

      this.router.navigate([], {
  relativeTo: this.activatedRoute,
  queryParams,
});

ВключениеscrollPositionRestorationрекомендуется Angular:

«включено» — восстанавливает предыдущую позицию прокрутки при навигации назад, в противном случае устанавливает позицию привязки, если она предусмотрена, или устанавливает позицию прокрутки на [0, 0] (навигация вперед). В будущем эта опция будет использоваться по умолчанию.

      RouterModule.forRoot(routes, { 
  scrollPositionRestoration: 'enabled', 
})

Но когда маршрут изменяется, Angular рассматривает простое изменение параметров запроса как «навигацию вперед», даже если сам маршрут остается прежним. В этом обходном пути используется попарная функция для сравнения текущих и предыдущих событий маршрутизатора и определения фактического изменения маршрута или только параметров маршрута (т. е. параметров запроса). ПРИМЕЧАНИЕ. Если этот запрос на функцию будет реализован, этот обходной путь больше не понадобится.

      export class AppModule {
  constructor(
    private router: Router,
    private viewportScroller: ViewportScroller,
  ) {
    this.viewportScroller.setHistoryScrollRestoration('manual'); // Disable automatic scroll restoration to avoid race conditions
    this.handleScrollOnNavigation();
  }

  private handleScrollOnNavigation(): void {
    this.router.events.pipe(
      // import { Event } from '@angular/router'
      filter((e: Event): e is Scroll => e instanceof Scroll),
      pairwise(),
    ).subscribe((e: Scroll[]) => {
      const previous = e[0];
      const current = e[1];

      if (current.position) {
        // Backward navigation
        this.viewportScroller.scrollToPosition(current.position);
      } else if (current.anchor) {
        // Anchor navigation
        this.viewportScroller.scrollToAnchor(current.anchor);
      } else {
        // Check if routes match, or if it is only a query param change
        if (this.getBaseRoute(previous.routerEvent.urlAfterRedirects) !== this.getBaseRoute(current.routerEvent.urlAfterRedirects)) {
          // Routes don't match, this is actual forward navigation
          // Default behavior: scroll to top
          this.viewportScroller.scrollToPosition([0, 0]);
        }
      }
    });
  }

  private getBaseRoute(url: string): string {
    // return url without query params
    return url.split('?')[0];
  }
}

Если он не работает с ScrollPositionRestoration: конфигурация 'enabled' используйте привязку свойства [scrollTop] для контейнера и присвойте значение

Если восстановление прокрутки не работает, создайте службу, которая обновляет текущую позицию прокрутки при изменении этого маршрута, и назначьте позицию прокрутки этой позиции прокрутки службы на ngOnit для нового компонента маршрута и сбросьте прокрутку службы.

Если у кого-то все еще есть проблемы с этим, есть решение.

  1. Сделайте сервис, в котором вы будете хранить позицию элемента
          @Injectable()
    export class AdsService {
     private _position = new BehaviorSubject<number>(0);

     constructor() {}

     get position$(): Observable<number> {
       return this._position.asObservable();
     }

     setPosition(position: number): void {
       this._position.next(position);
     }
   }
  1. Предоставьте услугу в модуле (например, AppModule) и внедрите ее в конструктор компонента.
  • Подпишитесь на позицию, проверьте, если не 0, и установите свойство "scrollTop" элемента
  • Напишите функцию savePositon, которая сохранит позицию после перехода к определенному элементу.
      export class MyComponent implements OnInit, OnDestroy, AfterViewInit {
  @ViewChild('contentArea') private contentArea: ElementRef<HTMLDivElement>;

  constructor(private adsService: AdsService) {}

  ngAfterViewInit(): void {
    this.adsService.position$
      .pipe(
        filter((p) => p !== 0),
        take(1)
      )
      .subscribe((p) => {
        this.contentArea.nativeElement.scrollTop = p;
      });
  }

  ngOnDestroy(): void {}

  ngOnInit(): void {}

  savePosition = () => {
    // this.router.navigate([item.id]);
    const scrollTop = this.contentArea.nativeElement.scrollTop;
    this.adsService.setPosition(scrollTop);
  };
}
  1. Мой фрагмент HTML выглядит примерно так
      <div #contentArea class="overflow">
   <div
    *ngFor="let item of activeAds; trackBy: trackByFn"
    [routerLink]="item.id"
    (click)="savePosition()"
   >
    {{item.name}}
   </div>
</div>
Другие вопросы по тегам