Sử dụng Router
chính nó sẽ gây ra các vấn đề mà bạn không thể khắc phục hoàn toàn để duy trì trải nghiệm trình duyệt nhất quán. Theo tôi phương pháp tốt nhất là chỉ sử dụng một tùy chỉnh directive
và để điều này thiết lập lại cuộn khi nhấp chuột. Điều tốt về điều này, là nếu bạn ở trên cùng url
khi bạn nhấp vào, trang cũng sẽ cuộn trở lại đầu trang. Điều này phù hợp với các trang web bình thường. Cơ bản directive
có thể trông giống như thế này:
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: '[linkToTop]'
})
export class LinkToTopDirective {
@HostListener('click')
onClick(): void {
window.scrollTo(0, 0);
}
}
Với cách sử dụng sau:
<a routerLink="/" linkToTop></a>
Điều này sẽ đủ cho hầu hết các trường hợp sử dụng, nhưng tôi có thể tưởng tượng một vài vấn đề có thể phát sinh từ điều này:
- Không hoạt động
universal
vì sử dụngwindow
- Tác động tốc độ nhỏ đến phát hiện thay đổi, bởi vì nó được kích hoạt bởi mỗi lần nhấp
- Không có cách nào để vô hiệu hóa chỉ thị này
Thực sự khá dễ dàng để khắc phục những vấn đề này:
@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)
);
}
}
}
Điều này đưa hầu hết các trường hợp sử dụng vào tài khoản, với cùng cách sử dụng như trường hợp cơ bản, với ưu điểm là bật / tắt nó:
<a routerLink="/" linkToTop></a> <!-- always active -->
<a routerLink="/" [linkToTop]="isActive"> <!-- active when `isActive` is true -->
quảng cáo, đừng đọc nếu bạn không muốn được quảng cáo
Một cải tiến khác có thể được thực hiện để kiểm tra xem trình duyệt có hỗ trợ passive
các sự kiện hay không . Điều này sẽ làm phức tạp mã hơn một chút và hơi tối nghĩa nếu bạn muốn thực hiện tất cả những điều này trong các chỉ thị / mẫu tùy chỉnh của mình. Đó là lý do tại sao tôi viết một thư viện nhỏ mà bạn có thể sử dụng để giải quyết những vấn đề này. Để có chức năng tương tự như trên và với passive
sự kiện được thêm vào , bạn có thể thay đổi chỉ thị của mình thành điều này, nếu bạn sử dụng ng-event-options
thư viện. Logic nằm bên trong click.pnb
người nghe:
@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' })