Die Verwendung von Routerselbst führt zu Problemen, die Sie nicht vollständig überwinden können, um eine konsistente Browser-Erfahrung zu gewährleisten. Meiner Meinung nach ist die beste Methode, einfach eine benutzerdefinierte zu verwenden directiveund die Schriftrolle beim Klicken zurücksetzen zu lassen. Das Gute daran ist, dass urldie Seite auch nach oben zurückblättert , wenn Sie sich auf der gleichen Seite befinden, auf die Sie geklickt haben. Dies steht im Einklang mit normalen Websites. Das Basic directivekönnte ungefähr so aussehen:
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: '[linkToTop]'
})
export class LinkToTopDirective {
@HostListener('click')
onClick(): void {
window.scrollTo(0, 0);
}
}
Mit folgender Verwendung:
<a routerLink="/" linkToTop></a>
Dies wird für die meisten Anwendungsfälle ausreichen, aber ich kann mir einige Probleme vorstellen, die sich daraus ergeben können:
- Funktioniert nicht
universalwegen der Verwendung vonwindow
- Geringe Geschwindigkeit wirkt sich auf die Änderungserkennung aus, da sie bei jedem Klick ausgelöst wird
- Keine Möglichkeit, diese Richtlinie zu deaktivieren
Es ist eigentlich ganz einfach, diese Probleme zu lösen:
@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)
);
}
}
}
Dies berücksichtigt die meisten Anwendungsfälle mit der gleichen Verwendung wie die Basis mit dem Vorteil, dass sie aktiviert / deaktiviert werden:
<a routerLink="/" linkToTop></a> <!-- always active -->
<a routerLink="/" [linkToTop]="isActive"> <!-- active when `isActive` is true -->
Werbespots, lesen Sie nicht, wenn Sie nicht beworben werden möchten
Eine weitere Verbesserung könnte vorgenommen werden, um zu überprüfen, ob der Browser passiveEreignisse unterstützt oder nicht . Dies macht den Code etwas komplizierter und ist etwas unklar, wenn Sie all dies in Ihre benutzerdefinierten Anweisungen / Vorlagen implementieren möchten. Deshalb habe ich eine kleine Bibliothek geschrieben, mit der Sie diese Probleme angehen können. Um die gleiche Funktionalität wie oben und mit dem hinzugefügten passiveEreignis zu haben, können Sie Ihre Direktive in diese ändern, wenn Sie die ng-event-optionsBibliothek verwenden. Die Logik ist im click.pnbHörer:
@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' })