JAvascriptカスタムスクロールバーの実装


実際の項目では、上下スクロールバーと左右スクロールバーが1つのDIV内部にないため、右側スクロールバーが表示されない場合があります.しかし、同じビューポートに2つのスクロールバーを表示する方法が必要です.
1つの解決策は、スクロールバーをカスタマイズし、元のスクロールバーを非表示にすることです.
スクロールバーのカスタマイズ
scrollbar.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import '../css/scrollbar.css';

const propTypes = {
  eventBus: PropTypes.object.isRequired,
};

class ScrollBar extends Component {

  constructor(props) {
    super(props);
    this.state = {
      isDraging: false,
      // X: bottom scrollbar offset left, range [0, innerWidth - 100]. When dragging, x is changing
      x: null,
      // clickX         ,                 , range [0, 100], When dragging, clickX isn't changing
      clickX: 0,
    };
  }

  componentDidMount() {
    this.unsubscribeScrollToColumn = this.props.eventBus.subscribe('set-scrollbar-left', this.setScrollBarLeft);
    document.addEventListener('mouseup', this.onMouseUp);
  }

  componentWillUnmount() {
    this.unsubscribeScrollToColumn();
    document.removeEventListener('mouseup', this.onMouseUp);
  }

  /**
   *         (     ,       )   100       
   */
  setScrollBarLeft = (leftRatio) => {
    // when bottom scrollbar is dragging, can't set scrollBa left
    if (this.state.isDraging) return;
    this.setState({
      x: (window.innerWidth - 100) * leftRatio,
    });
  }

  /**
   *      ,    ,               
   */
  handleMouseDown = (e) => {
    this.setState({
      isDraging: true,
      clickX: e.nativeEvent.offsetX,
    });
  }

  /**
   *       ,    ,          0(         )
   */
  onMouseUp = () => {
    if (this.state.isDraging) {
      setTimeout(() => {
        this.setState({ isDraging: false, clickX: 0 });
      }, 100);
    }
  }

  /**
   *       (         ),       ,       
   *   :      ,      
   *       ,          ,  Grid    
   *      ,               ,        
   * */ 
  onMouseMove = (e) => {
    e.persist();
    if (this.state.isDraging) {
      //     =      + (        -        )
      let newX = this.state.x + e.nativeEvent.offsetX - this.state.clickX;
      newX = Math.min(newX, window.innerWidth - 100); //              
      this.setState({ x: newX });
      const leftRatio = newX / (window.innerWidth - 100);
    }
  }

  renderBottomToolbar = () => {
    return (
      <div
        className="antiscroll-scrollbar antiscroll-scrollbar-horizontal antiscroll-scrollbar-shown"
        style={{transform: `translateX(${this.state.x}px)`}}
        draggable="true"
        onMouseDown={this.handleMouseDown}
        onMouseMove={this.onMouseMove}
        onMouseUp={this.onMouseUp}
      ></div>
    );
  }

  // todo: rightToolbar event handle
  renderRightToolbar = () => {
    return (
      <div
        className="antiscroll-scrollbar antiscroll-scrollbar-vertical antiscroll-scrollbar-shown"
      ></div>
    );
  }

  render() {
    return (
      <div id="scrollOverlay" className="antiscroll-wrap">
        {this.renderBottomToolbar()}
        {this.renderRightToolbar()}
      </div>
    );
  }
}

ScrollBar.propTypes = propTypes;

export default ScrollBar;

スクロールバースタイル
対応するscrollbar.css
#scrollOverlay {
  display: inline-block;
  overflow: hidden;
  position: fixed;
  left: 0;
  right: 0;
  top: 156px;
  bottom: 0;
  z-index: 4;
  pointer-events: none;
  opacity: .7;
}

#scrollOverlay .antiscroll-scrollbar {
  pointer-events: auto;
  z-index: 2;
  background-color: hsla(0,0%,0%,0.28);
  box-shadow: inset 0 0 0 1px hsl(0,0%,100%);
  border-radius: 5px;
}

#scrollOverlay .antiscroll-scrollbar-horizontal {
  height: 12px;
  width: 100px;
  position: absolute;
  bottom: 32px;
}

#scrollOverlay .antiscroll-scrollbar-vertical {
  width: 12px;
  height: 100px;
  position: absolute;
  right: 0;
}

/*              */
.react-demo::-webkit-scrollbar {
  width: 0;
}

スクロールバーの使用方法
具体的にはGridにこのスクロールバーを追加します
import ScrollBar from '../components/scrollbar';

// Grid     ,      
onScroll = () => {
  // todo: when clientWidth is smaller than innerWidth, don't show bottom scrollBar
  let scrollLeftRatio = this._scrollLeft / (clientWidth - window.innerWidth);
  //    DOM     ,         (   /    ),          
  this.setScrollLeftRatio(scrollLeftRatio);
}

setScrollLeftRatio = (scrollLeftRatio) => {
  this.props.eventBus.dispatch('set-scrollbar-left', scrollLeftRatio);
}

//         ,  eventBus,        
// 

カスタムスクロールバーにはオープンソースサードパーティコンポーネントも多数あります.サードパーティ製ライブラリを優先して実装します(スクロールバーの計算を処理する場合が多い)