Bilah gulir khusus di Sudut

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'))
      );
    })
  );

. , .


All Articles