`
"use client"
/*
* 自定义一个滚动区域
* */
import {useEffect, useRef, useState} from "react";
import _ from "lodash"
import {useMutationObserver, useSize} from "ahooks";
export default function Page(props: any) {
// 最外层容器元素
const wrapperRef = useRef<any>(null)
// 滚动外层元素
const containerRef = useRef<any>(null)
const rongqiRef = useRef<any>(null)
// 滚动条垂直
// 滚动条初始位置
const [position, setPosition] = useState({
x: 0,
y: 0
})
// 判断内容是否超出容器,进而显示滚动条
const [showVertical, setShowVertical] = useState(false)
const [showHorizontal, setShowHorizontal] = useState(false)
// 垂直滑块的高度和水平滑块的宽度
const [verticalHeight, setVerticalHeight] = useState(0)
const [horizontalWidth, setHorizontalWidth] = useState(0)
// 垂直滚动百分比
const [verticalPercent, setVerticalPercent] = useState(0)
const [horizontalPercent, setHorizontalPercent] = useState(0)
// 滚轮事件
const gundongFunc = (e: any) => {
if (!containerRef.current) {
return
}
containerRef.current.scrollTop = containerRef.current.scrollTop + e.deltaY / 2
}
// 垂直滑块拖动事件
const tuodongFunc = (e: any) => {
const chushiY = e.clientY
const chushitop = containerRef.current.scrollTop
document.onmousemove = (e2) => {
const chushiY2 = e2.clientY
const chazhi = chushiY2 - chushiY
const heightDif = sizeWaibu?.height - verticalHeight
const bili = chazhi / heightDif
const height = sizeNeibu?.height - sizeWaibu?.height
containerRef.current.scrollTop = chushitop + bili * height
}
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
}
}
// 水平滑块拖动事件
const tuodongFunc2 = (e: any) => {
console.log("水平滚动条的拖动事件触发")
const chushiX = e.clientX
const chushiLeft = containerRef.current.scrollLeft
document.onmousemove = (e2) => {
const chushiX2 = e2.clientX
const chazhi = chushiX2 - chushiX
const widthDif = sizeWaibu?.width - horizontalWidth
const bili = chazhi / widthDif
const width = sizeNeibu?.width - sizeWaibu?.width
containerRef.current.scrollLeft = chushiLeft + bili * width
}
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
}
}
// 获取当前最新的位置
const getPosition = (e: any) => {
const data = {
x: containerRef.current.scrollLeft,
y: containerRef.current.scrollTop
}
console.log("当前的定位:", data)
setPosition(data)
updateScroll(data)
}
// 更新滑块的位置
const updateScroll = (data) => {
// 如果显示滚动条,更新滑块的位置
if (showVertical && props.verticalScroll) {
// 首先获取内容高度和视口高度的差
const height = sizeNeibu?.height - sizeWaibu?.height
// 获取轨道和滑块的高度差
const heightDif = sizeWaibu?.height - verticalHeight
setVerticalPercent(data.y / height * heightDif)
}
if (showHorizontal && props.horizontalScroll) {
// 首先获取内容高度和视口高度的差
const width = sizeNeibu?.width - sizeWaibu?.width
// 获取轨道和滑块的高度差
const widthDif = sizeWaibu?.width - horizontalWidth
setHorizontalPercent(data.x / width * widthDif)
}
}
// 监听内容的宽高
const sizeNeibu = useSize(rongqiRef);
const sizeWaibu = useSize(containerRef);
useEffect(() => {
console.log("触发大小改变:", sizeNeibu?.width, sizeWaibu?.width,)
if (sizeNeibu?.width > sizeWaibu?.width) {
setShowHorizontal(sizeNeibu?.width > sizeWaibu?.width)
setHorizontalWidth(sizeWaibu?.width * sizeWaibu?.width / sizeNeibu?.width)
} else {
setShowHorizontal(sizeNeibu?.width > sizeWaibu?.width)
setHorizontalWidth(0)
}
if (sizeNeibu?.height > sizeWaibu?.height) {
setShowVertical(sizeNeibu?.height > sizeWaibu?.height)
setVerticalHeight(sizeWaibu?.height * sizeWaibu?.height / sizeNeibu?.height)
} else {
setShowVertical(sizeNeibu?.height > sizeWaibu?.height)
setVerticalHeight(0)
}
}, [sizeNeibu, sizeWaibu])
// 垂直滚动条渲染
const verticalScrollRender = () => <div
className={"absolute top-0 right-0 bottom-0 w-8px bg-transparent overflow-hidden select-none flex justify-center"}>
<div onMouseDown={tuodongFunc} className={"absolute right-0 w-8px bg-gray-400 rounded-full"}
style={{height: `${verticalHeight}px`, top: `${verticalPercent}px`}}/>
</div>
// 水平滚动条渲染
const horizontalScrollRender = () => <div
className={"absolute left-0 right-0 bottom-0 h-10px bg-transparent overflow-hidden flex items-center"}>
<div onMouseDown={tuodongFunc2} className={"absolute bottom-0 h-8px bg-blue-400 rounded-full"}
style={{width: `${horizontalWidth}px`, left: `${horizontalPercent}px`}}/>
</div>
return (
<div ref={wrapperRef} className={["relative", props.class || ""].join(" ")} style={{...(props.style || {})}}>
<div onWheel={gundongFunc}
onScroll={getPosition}
ref={containerRef}
className={["w-full h-full overflow-scroll", props.contentClass || ""].join(" ")}
style={{scrollbarWidth: "none", ...(props.contentStyle || {})}}>
<div ref={rongqiRef} className={"min-w-full w-fit min-h-full"}>
{props.children}
</div>
</div>
{props.verticalScroll && verticalHeight && verticalScrollRender()}
{props.horizontalScroll && horizontalWidth && horizontalScrollRender()}
</div>
)
}