JAvascriptカスタムスクロールバーの実装
実際の項目では、上下スクロールバーと左右スクロールバーが1つのDIV内部にないため、右側スクロールバーが表示されない場合があります.しかし、同じビューポートに2つのスクロールバーを表示する方法が必要です.
1つの解決策は、スクロールバーをカスタマイズし、元のスクロールバーを非表示にすることです.
スクロールバーのカスタマイズ
scrollbar.js
スクロールバースタイル
対応するscrollbar.css
スクロールバーの使用方法
具体的にはGridにこのスクロールバーを追加します
カスタムスクロールバーにはオープンソースサードパーティコンポーネントも多数あります.サードパーティ製ライブラリを優先して実装します(スクロールバーの計算を処理する場合が多い)
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,
//
カスタムスクロールバーにはオープンソースサードパーティコンポーネントも多数あります.サードパーティ製ライブラリを優先して実装します(スクロールバーの計算を処理する場合が多い)