Nachdem Edge zu den tapferen Reihen der Chromium-Browser gehört hat, fehlt die Anpassung der Bildlaufleisten über CSS nur in Firefox. Es ist großartig, aber neben Firefox hat die CSS-Lösung eine Menge Einschränkungen. Sehen Sie, welche schwarze Magie Sie zum Ausblenden verwenden müssen. Um die volle Kontrolle über das Erscheinungsbild zu erhalten, müssen Sie immer noch auf JavaScript zurückgreifen. Mal sehen, wie man es auf gute Weise durch die Angular-Komponente macht.

CSS-Magie
, , . -, . . 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'))
);
})
);
. , .