Die Verwendung von Router
selbst 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 directive
und die Schriftrolle beim Klicken zurücksetzen zu lassen. Das Gute daran ist, dass url
die 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 directive
kö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
universal
wegen 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 passive
Ereignisse 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 passive
Ereignis zu haben, können Sie Ihre Direktive in diese ändern, wenn Sie die ng-event-options
Bibliothek verwenden. Die Logik ist im click.pnb
Hö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' })