tiefen_space_h5/components/MySlider/index.jsx

327 lines
9.1 KiB
JavaScript

import React, { useState, useEffect, useRef } from "react";
export default function MySlider({
lower_bound,
upper_bound,
step,
unit,
unitSite = "right",
width = 0,
onChange,
handleFunc = () => {},
disabled = false,
thumbSize = 25,
stepValues = [],
hasInfinity,
leftValue = lower_bound,
rightValue = stepValues[stepValues.length - 1],
maximumTrackTintColor = "#dcdbdb",
minimumTrackTintColor = "#577BFF",
processHeight = 7,
}) {
// const leftProcess = useRef(0);
// const rightProcess = useRef(0);
const [leftProcess, setLeftProcess] = useState(0);
const [rightProcess, setRightProcess] = useState(0);
const [stepNum, setStepNum] = useState(stepValues.length - 1);
const [processWidth, setProcessWidth] = useState(330);
const currentLeftValue = useRef(leftValue);
const currentRightValue = useRef(rightValue);
useEffect(() => {
setProcessWidth(width - thumbSize * 2);
}, []);
useEffect(() => {
const currentLeftProcess =
(stepValues.indexOf(leftValue) * step - lower_bound) /
(upper_bound - lower_bound);
const currentRightProcess =
(stepValues.indexOf(rightValue) * step - lower_bound) /
(upper_bound - lower_bound);
setLeftProcess(currentLeftProcess);
setRightProcess(currentRightProcess);
currentLeftValue.current = leftValue;
currentRightValue.current = rightValue;
}, [leftValue, rightValue]);
// 左侧滑块事件
const _onPanResponderGrantLeft = () => {
handleFunc && handleFunc();
};
const _onPanResponderEndLeft = () => {
handleFunc && handleFunc();
};
const _onPanResponderMoveLeft = (e) => {
if (e.touches.length == 1) {
const process = (e.touches[0].pageX - thumbSize * 2) / processWidth;
_changeProcess(process, "left");
}
};
// 右侧滑块事件
const _onPanResponderGrantRight = (e, gestureState) => {
handleFunc && handleFunc();
};
const _onPanResponderEndRight = (e, gestureState) => {
handleFunc && handleFunc();
};
const _onPanResponderMoveRight = (e) => {
if (e.touches.length == 1) {
const process = (e.touches[0].pageX - thumbSize / 2 - 40) / processWidth;
_changeProcess(process, "right");
}
};
const _changeProcess = (changeProcess, direction) => {
// 判断滑动开关
if (disabled) return;
// 按步长比例变化刻度
changeProcess =
changeProcess > 1 ? 1 : changeProcess < 0 ? 0 : changeProcess;
const v = changeProcess * (upper_bound - lower_bound);
const newValue = Math.round(v / step) * step;
const newProcess = Math.round(newValue) / (upper_bound - lower_bound);
setStepNum(stepNum + 1);
if (process !== newProcess) {
if (direction == "left") {
const currentRightProcess =
(stepValues.indexOf(currentRightValue.current) * step - lower_bound) /
(upper_bound - lower_bound);
if (newProcess < currentRightProcess) {
const newLower =
stepValues[
Math.round(
(newProcess * (upper_bound - lower_bound) + lower_bound) / step
)
];
if (newLower <= currentRightValue.current - 3) {
setLeftProcess(newProcess);
setStepNum((old) => old + 1);
onChange({
lower_bound: newLower,
upper_bound: currentRightValue.current,
});
}
}
} else {
const currentLeftProcess =
(stepValues.indexOf(currentLeftValue.current) * step - lower_bound) /
(upper_bound - lower_bound);
if (newProcess > currentLeftProcess) {
const newUpper =
stepValues[
Math.round(
(newProcess * (upper_bound - lower_bound) + lower_bound) / step
)
];
if (newUpper >= currentLeftValue.current + 3) {
setRightProcess(newProcess);
setStepNum((old) => old - 1);
onChange({
lower_bound: currentLeftValue.current,
upper_bound: newUpper,
});
}
// setStepNum(stepNum - 1);
}
}
}
};
return (
<div
className="flex relative "
style={{
// height: "upper_bound-content",
width,
// flex: 1,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
marginBottom: 36,
marginTop: 24,
}}
>
<div style={{ width: "100%", position: "relative" }}>
{/* 格子步数 */}
{hasInfinity && (
<div
className="flex flex-row justify-between items-center absolute"
style={{
top: -23,
flex: 1,
width: "100%",
// height: 40,
padding: 17,
paddingRight: 20,
marginLeft: -12,
// backgroundColor: "#fff",
}}
>
{stepValues.map((item, index) => (
<div
key={index}
style={{
backgroundColor:
item >= leftValue && item <= rightValue
? minimumTrackTintColor
: maximumTrackTintColor,
width: thumbSize / 2,
height: thumbSize / 2,
borderRadius: 50,
}}
></div>
))}
</div>
)}
<div
style={{
backgroundColor: maximumTrackTintColor,
height: processHeight,
width: processWidth,
position: "absolute",
marginTop: -processHeight / 2,
left: thumbSize / 2,
zIndex: 1,
borderRadius: 50,
}}
/>
<div
style={{
backgroundColor: minimumTrackTintColor,
width: (rightProcess - leftProcess) * processWidth,
height: processHeight,
marginLeft: thumbSize / 2 + leftProcess * processWidth,
position: "absolute",
marginTop: -processHeight / 2,
left: 0,
zIndex: 10,
borderRadius: 50,
}}
/>
</div>
{/* 左侧控件 */}
<div
transition={1000}
// style={tailwind("w-full h-full rounded-lg overflow-hidden")}
style={{
position: "absolute",
left: leftProcess * processWidth,
zIndex: 10,
width: thumbSize,
height: thumbSize,
borderRadius: 50,
backgroundColor: "#ff75c8",
borderColor: "#ffffff",
borderWidth: 2,
}}
draggable={true}
onTouchStart={_onPanResponderGrantLeft}
onTouchMove={_onPanResponderMoveLeft}
onTouchEnd={_onPanResponderEndLeft}
></div>
{/* 右侧控件 */}
<div
transition={1000}
// style={tailwind("w-full h-full rounded-lg overflow-hidden")}
style={{
position: "absolute",
left: rightProcess * processWidth,
zIndex: 10,
width: thumbSize,
height: thumbSize,
backgroundColor: "#fff",
borderRadius: 50,
backgroundColor: "#ff75c8",
borderColor: "#ffffff",
borderWidth: 2,
}}
draggable={true}
onTouchStart={_onPanResponderGrantRight}
onTouchMove={_onPanResponderMoveRight}
onTouchEnd={_onPanResponderEndRight}
></div>
<div
className="flex flex-row justify-between items-center absolute text-lg"
style={{
top: -48,
right: 24,
}}
>
{unitSite == "left" && (
<span
style={{
maxWidth: thumbSize * 2,
color: "#ff75c8",
}}
>
{unit}
</span>
)}
<span
style={{
color: "#ff75c8",
}}
>
{hasInfinity && leftProcess == 1 ? "∞" : leftValue}
</span>
<span
style={{
marginHorizontal: 4,
color: "#ff75c8",
}}
>
~
</span>
<span
className={hasInfinity ? "text-xl" : ""}
style={{
color: "#ff75c8",
}}
>
{hasInfinity && rightProcess >= 1 ? "∞" : rightValue}
</span>
{unitSite == "right" && (
<span
style={{
maxWidth: thumbSize * 2,
color: "#ff75c8",
}}
>
{unit}
</span>
)}
</div>
<div
className="absolute text-white text-sm flex flex-row justify-between"
style={{
width: width - 22,
left: 0,
top: 20,
color: "#ffffff80",
}}
>
<span
className="text-sm"
style={{
minWidth: thumbSize,
maxWidth: thumbSize * 2,
color: "#ffffff80",
}}
>
{lower_bound}
</span>
<span
style={{
minWidth: thumbSize,
color: "#ffffff80",
}}
>
{hasInfinity ? "∞" : upper_bound}
</span>
</div>
</div>
);
}