Использование самого Routerсебя вызовет проблемы, которые вы не можете полностью преодолеть, чтобы поддерживать постоянную работу браузера. На мой взгляд, лучший способ - просто использовать кастом directiveи позволить этому сбросить прокрутку по клику. Хорошая вещь об этом, то, что, если вы находитесь на том же самом, urlчто вы нажимаете, страница также будет прокручиваться вверх. Это соответствует нормальным веб-сайтам. Основное directiveможет выглядеть примерно так:
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: '[linkToTop]'
})
export class LinkToTopDirective {
@HostListener('click')
onClick(): void {
window.scrollTo(0, 0);
}
}
Со следующим использованием:
<a routerLink="/" linkToTop></a>
Этого будет достаточно для большинства вариантов использования, но я могу представить несколько проблем, которые могут возникнуть из этого:
- Не работает
universalиз-за использованияwindow
- Небольшое влияние скорости на обнаружение изменений, потому что оно срабатывает при каждом нажатии
- Нет способа отключить эту директиву
На самом деле это довольно легко преодолеть эти проблемы:
@Directive({
selector: '[linkToTop]'
})
export class LinkToTopDirective implements OnInit, OnDestroy {
@Input()
set linkToTop(active: string | boolean) {
this.active = typeof active === 'string' ? active.length === 0 : active;
}
private active: boolean = true;
private onClick: EventListener = (event: MouseEvent) => {
if (this.active) {
window.scrollTo(0, 0);
}
};
constructor(@Inject(PLATFORM_ID) private readonly platformId: Object,
private readonly elementRef: ElementRef,
private readonly ngZone: NgZone
) {}
ngOnDestroy(): void {
if (isPlatformBrowser(this.platformId)) {
this.elementRef.nativeElement.removeEventListener('click', this.onClick, false);
}
}
ngOnInit(): void {
if (isPlatformBrowser(this.platformId)) {
this.ngZone.runOutsideAngular(() =>
this.elementRef.nativeElement.addEventListener('click', this.onClick, false)
);
}
}
}
Это учитывает большинство сценариев использования, при том же использовании, что и основной, с преимуществом включения / выключения:
<a routerLink="/" linkToTop></a> <!-- always active -->
<a routerLink="/" [linkToTop]="isActive"> <!-- active when `isActive` is true -->
рекламные ролики, не читайте, если вы не хотите, чтобы вас рекламировали
Еще одно улучшение может быть сделано, чтобы проверить, поддерживает ли браузер passiveсобытия. Это немного усложнит код и будет немного неясным, если вы захотите реализовать все это в своих пользовательских директивах / шаблонах. Вот почему я написал небольшую библиотеку, которую вы можете использовать для решения этих проблем. Чтобы иметь ту же функциональность, что и выше, и с добавленным passiveсобытием, вы можете изменить свою директиву на эту, если вы используете ng-event-optionsбиблиотеку. Логика внутри click.pnbслушателя:
@Directive({
selector: '[linkToTop]'
})
export class LinkToTopDirective {
@Input()
set linkToTop(active: string|boolean) {
this.active = typeof active === 'string' ? active.length === 0 : active;
}
private active: boolean = true;
@HostListener('click.pnb')
onClick(): void {
if (this.active) {
window.scrollTo(0, 0);
}
}
}
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })