การใช้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' })