Setelah Edge bergabung dengan barisan browser Chromium yang gagah berani, kustomisasi scrollbar melalui CSS tidak ada di Firefox. Ini hebat, tetapi selain dari Firefox, solusi CSS memiliki banyak keterbatasan. Lihat sihir hitam apa yang harus Anda gunakan untuk menghilang. Untuk mendapatkan kontrol penuh atas penampilan, Anda masih perlu menggunakan JavaScript. Mari kita lihat bagaimana melakukannya melalui komponen Angular dengan cara yang baik.

Keajaiban CSS
, , . -, . . scrollbar-width
, Firefox. Edge IE -ms-overflow-style
. IE , position: sticky
. Chrome Safari ::-webkit-scrollbar
.
-, , . , - position: fixed
. : .
position: sticky
display: flex
. :
<div class="bars">...</div>
<div class="content"><ng-content></ng-content></div>
. , - z-index: 1000, 1001, 9999
. , position: relative, z-index: 0
. - .
z-index: 1
, , 100%. :

, . . margin-right: -100%
, «» .
, , float
, 100%, (max-height, flex: 1
).
Angular
Angular, , . . . , . :
<div class="bars">
<div *ngIf="hasVerticalBar" class="bar">
<div
class="thumb"
[class.thumb_active]="verticalThumbActive"
[style.height.%]="verticalView"
[style.top.%]="verticalThumb"
></div>
</div>
</div>
:
//
get verticalScrolled(): number {
const {
scrollTop,
scrollHeight,
clientHeight
} = this.elementRef.nativeElement;
return scrollTop / (scrollHeight - clientHeight);
}
//
get verticalSize(): number {
const { clientHeight, scrollHeight } = this.elementRef.nativeElement;
return Math.ceil(clientHeight / scrollHeight * 100);
}
//
get verticalPosition(): number {
return this.verticalScrolled * (100 - this.verticalSize);
}
// ,
get hasVerticalBar(): boolean {
return this.verticalSize < 100;
}
, , β . . , .
mousedown
, mousemove
mouseup
.
:
<div
#vertical
class="thumb"
[class.thumb_active]="verticalThumbActive"
[style.height.%]="verticalSize"
[style.top.%]="verticalPosition"
(mousedown)="onVerticalStart($event)"
(document:mousemove)="onVerticalMove($event, vertical)"
></div>
mouseup
:
@HostListener('document:mouseup)
onDragEnd() {
this.verticalThumbActive = false;
}
onVerticalStart(event: MouseEvent) {
event.preventDefault();
const { target, clientY } = event;
const { top, height } = target.getBoundingClientRect();
this.verticalThumbDragOffset = (clientY - top) / height;
this.verticalThumbActive = true;
}
onVerticalMove(
{ clientY }: MouseEvent,
{ offsetHeight }: HTMLElement
) {
if (!this.verticalThumbActive) {
return;
}
const { nativeElement } = this.elementRef;
const { top, height } = nativeElement.getBoundingClientRect();
const maxScrollTop = nativeElement.scrollHeight - height;
const scrolled =
(clientY - top - offsetHeight * this.verticalThumbDragOffset) /
(height - offsetHeight);
nativeElement.scrollTop = maxScrollTop * scrolled;
}
.
Angular
, . mousemove
. . , Angular , . @tinkoff/ng-event-plugins, . .silent
@shouldCall
:
(document:mousemove.silent)="onVerticalMove($event, vertical)"
@shouldCall(isActive)
@HostListener('init.end', ['$event'])
@HostListener('document:mouseup.silent')
onDragEnd() {
this.verticalThumbActive = false;
}
@shouldCall(isActive)
@HostListener('init.move', ['$event'])
onVerticalMove(
{ clientY }: MouseEvent,
{ offsetHeight }: HTMLElement
) {
const { nativeElement } = this.elementRef;
const { top, height } = nativeElement.getBoundingClientRect();
const maxScrollTop = nativeElement.scrollHeight - height;
const scrolled =
(clientY - top - offsetHeight * this.verticalThumbDragOffset) /
(height - offsetHeight);
nativeElement.scrollTop = maxScrollTop * scrolled;
}
: Angular 10 markDirty(this)
@shouldCall
@HostListener(βinit.xxxβ, [β$eventβ])
, , β .
, . . , . ResizeObserver
@ng-web-apis/resize-observer, . Stackblitz.
Edit:
, , . . Output fromEvent, :
@Output()
dragged = fromEvent(
this.elementRef.nativeElement,
'mousedown'
).pipe(
switchMap(event => {
event.preventDefault();
const clientRect = event.target.getBoundingClientRect();
const offsetVertical = getOffsetVertical(event, clientRect);
const offsetHorizontal = getOffsetHorizontal(event, clientRect);
return fromEvent(this.documentRef, 'mousemove').pipe(
map(event => this.getScrolled(event, offsetVertical, offsetHorizontal)),
takeUntil(fromEvent(this.documentRef, 'mouseup'))
);
})
);
. , .