L'uso dello Router
stesso causerà problemi che non è possibile superare completamente per mantenere un'esperienza browser coerente. A mio avviso, il metodo migliore è utilizzare solo un'usanza personalizzata directive
e lasciare che questo ripristini lo scorrimento al clic. La cosa positiva di questo è che se sei uguale url
a quello su cui fai clic, anche la pagina tornerà all'inizio. Ciò è coerente con i normali siti Web. La base directive
potrebbe assomigliare a questa:
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: '[linkToTop]'
})
export class LinkToTopDirective {
@HostListener('click')
onClick(): void {
window.scrollTo(0, 0);
}
}
Con il seguente utilizzo:
<a routerLink="/" linkToTop></a>
Questo sarà sufficiente per la maggior parte dei casi d'uso, ma posso immaginare alcuni problemi che potrebbero derivare da questo:
- Non funziona a
universal
causa dell'uso diwindow
- Impatto a velocità ridotta sul rilevamento delle modifiche, poiché viene attivato da ogni clic
- Nessun modo per disabilitare questa direttiva
In realtà è abbastanza facile superare questi problemi:
@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)
);
}
}
}
Ciò tiene conto della maggior parte dei casi d'uso, con lo stesso utilizzo di quello di base, con il vantaggio di abilitarlo / disabilitarlo:
<a routerLink="/" linkToTop></a> <!-- always active -->
<a routerLink="/" [linkToTop]="isActive"> <!-- active when `isActive` is true -->
spot pubblicitari, non leggere se non vuoi essere pubblicizzato
Un altro miglioramento potrebbe essere fatto per verificare se il browser supporta o meno gli passive
eventi. Ciò complicherà un po 'di più il codice ed è un po' oscuro se si desidera implementare tutto ciò nelle direttive / modelli personalizzati. Ecco perché ho scritto una piccola biblioteca che puoi usare per affrontare questi problemi. Per avere le stesse funzionalità di cui sopra e con l' passive
evento aggiunto , è possibile modificare la direttiva in questo modo, se si utilizza la ng-event-options
libreria. La logica è dentro l' click.pnb
ascoltatore:
@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' })