Угловой 6 - сохранить положение прокрутки при изменении маршрута
Предыдущее поведение:
Изменение маршрута или пути навигации не повлияет на положение прокрутки при переходе на другой маршрут. Т.е. содержимое может меняться без изменения положения прокрутки.
Текущее поведение:
Изменение маршрута вернет вас обратно в начало страницы.
Действие сделано до сих пор:
Проверено на текущем и новом новом проекте Angular 6
Это ошибка? изменить функцию? или есть параметр, который я пропускаю.
6 ответов
Похоже, установка scrollPositionRestoration на отключенный исправляет это
RouterModule.forRoot(
appRoutes,
{ scrollPositionRestoration: 'disabled' } // <-- HERE
)
Положение прокрутки не изменится после изменения маршрута. Это всегда поведение по умолчанию для 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 для нового компонента маршрута и сбросьте прокрутку службы.
Если у кого-то все еще есть проблемы с этим, есть решение.
- Сделайте сервис, в котором вы будете хранить позицию элемента
@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);
}
}
- Предоставьте услугу в модуле (например, 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);
};
}
- Мой фрагмент HTML выглядит примерно так
<div #contentArea class="overflow">
<div
*ngFor="let item of activeAds; trackBy: trackByFn"
[routerLink]="item.id"
(click)="savePosition()"
>
{{item.name}}
</div>
</div>