javascript Realizes Custom Scroll Bar Effect
- 2021-11-13 00:33:37
- OfStack
In real projects, the up and down scroll bars and the left and right scroll bars are not inside 1 DIV, so in some cases, the right scroll bar is not visible. However, it is necessary to display two scroll bars in the same viewport.
One solution is to customize the scroll bar and hide the original scroll bar.
Custom scroll bar
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 Indicates the distance between the mouse click position and the left side of the scroll bar when dragging the scroll bar , 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);
}
/**
* This function handles linkage (when the interface scrolls, it triggers the scroll bar to scroll). 100 Is the width of the scroll bar
*/
setScrollBarLeft = (leftRatio) => {
// when bottom scrollbar is dragging, can't set scrollBa left
if (this.state.isDraging) return;
this.setState({
x: (window.innerWidth - 100) * leftRatio,
});
}
/**
* When the mouse is pressed, start dragging, and set the current position as the initial dragging position
*/
handleMouseDown = (e) => {
this.setState({
isDraging: true,
clickX: e.nativeEvent.offsetX,
});
}
/**
* When the mouse is raised, stop dragging and set the current click position to 0 (Is it necessary to set this)
*/
onMouseUp = () => {
if (this.state.isDraging) {
setTimeout(() => {
this.setState({ isDraging: false, clickX: 0 });
}, 100);
}
}
/**
* While dragging (mouse down and moving), get the current displacement and calculate the new offset
* Note: You can scroll to the right, you can scroll to the left
* When dragging is going on, you should calculate the current scale, and then Grid Horizontal rolling
* Now, if the mouse moves to the outside of the scroll bar when dragging, the dragging cannot be triggered
* */
onMouseMove = (e) => {
e.persist();
if (this.state.isDraging) {
// New distance = Original distance + (Current scrolling distance - Initial scroll distance)
let newX = this.state.x + e.nativeEvent.offsetX - this.state.clickX;
newX = Math.min(newX, window.innerWidth - 100); // The maximum drag cannot exceed the right boundary
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;
Scroll bar style
Corresponding 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;
}
/* Hide the scroll bar of the original scroll object */
.react-demo::-webkit-scrollbar {
width: 0;
}
Specific use of scroll bars
For specific use, we added this scroll bar in Grid
import ScrollBar from '../components/scrollbar';
// Grid Native scroll, triggering callback function
onScroll = () => {
// todo: when clientWidth is smaller than innerWidth, don't show bottom scrollBar
let scrollLeftRatio = this._scrollLeft / (clientWidth - window.innerWidth);
// When native DOM When scrolling left and right, get the proportion (offset) of the current scroll / Full width) and set the scroll bar to scroll
this.setScrollLeftRatio(scrollLeftRatio);
}
setScrollLeftRatio = (scrollLeftRatio) => {
this.props.eventBus.dispatch('set-scrollbar-left', scrollLeftRatio);
}
// In the original scroll element, pass in eventBus Which is convenient for event value transfer processing
// <ScrollBar eventBus={this.props.eventBus}/>
Custom scrollbars also have many open source third-party components, and we prefer to use the third-party library to implement them. (There are many considerations for handling scroll bar calculations.)