Files
mini-programs/src/components/NTRPSlider/NTRPSlider.tsx
2025-08-17 22:58:00 +08:00

134 lines
4.0 KiB
TypeScript

import React, { useState, useCallback } from 'react'
import { View, Text } from '@tarojs/components'
import Taro from '@tarojs/taro'
import './NTRPSlider.scss'
export interface NTRPRange {
min: number
max: number
}
// 获取NTRP显示文本的工具函数
export const getNTRPRangeText = (range: NTRPRange): string => {
if (range.min === 2.0 && range.max === 4.0) {
return '不限'
}
return `${range.min} - ${range.max}`
}
interface NTRPSliderProps {
value: NTRPRange
onChange: (range: NTRPRange) => void
title?: string
showTitle?: boolean
}
const NTRPSlider: React.FC<NTRPSliderProps> = ({
value = {
min: 1.0,
max: 5.0
},
onChange,
title = 'NTRP水平要求',
showTitle = false
}) => {
const [activeThumb, setActiveThumb] = useState<'min' | 'max' | null>(null)
// 计算滑动条位置百分比
const getSliderPercentage = useCallback((level: number) => {
return ((level - 2.0) / 2.0) * 100
}, [])
// 获取当前NTRP显示文本
const currentRangeText = getNTRPRangeText(value)
const handleSliderTouchStart = useCallback((thumb: 'min' | 'max') => {
setActiveThumb(thumb)
}, [])
const handleSliderTouchMove = useCallback((e: any) => {
if (!activeThumb) return
e.preventDefault()
const query = Taro.createSelectorQuery()
query.select('.ntrp-slider-track').boundingClientRect((rect: any) => {
if (rect && !Array.isArray(rect)) {
const touch = e.touches[0]
const relativeX = touch.clientX - rect.left
const percentage = Math.max(0, Math.min(1, relativeX / rect.width))
const level = Number((2.0 + percentage * 2.0).toFixed(1))
if (activeThumb === 'min') {
const newMin = Math.min(level, value.max - 0.1)
onChange({ min: newMin, max: value.max })
} else {
const newMax = Math.max(level, value.min + 0.1)
onChange({ min: value.min, max: newMax })
}
}
}).exec()
}, [activeThumb, value, onChange])
const handleSliderTouchEnd = useCallback(() => {
setActiveThumb(null)
}, [])
return (
<View className='ntrp-slider'>
{showTitle && (
<View className='section-title-wrapper'>
<Text className='section-title'>{title}</Text>
<Text className='section-summary'>{currentRangeText}</Text>
</View>
)}
<View className='ntrp-control-section'>
<View className='ntrp-slider-container'>
<View className='ntrp-labels'>
<Text className='ntrp-label'>2.0</Text>
<Text className='ntrp-label'>4.0</Text>
</View>
<View
className='ntrp-slider-track'
onTouchMove={handleSliderTouchMove}
onTouchEnd={handleSliderTouchEnd}
>
{/* 背景轨道 */}
<View className='slider-bg'></View>
{/* 选中区间 */}
<View
className='slider-range'
style={{
left: `${getSliderPercentage(value.min)}%`,
width: `${getSliderPercentage(value.max) - getSliderPercentage(value.min)}%`
}}
></View>
{/* 最小值滑块 */}
<View
className={`slider-thumb ${activeThumb === 'min' ? 'active' : ''}`}
style={{ left: `${getSliderPercentage(value.min)}%` }}
onTouchStart={() => handleSliderTouchStart('min')}
>
<View className='thumb-value'>{value.min}</View>
</View>
{/* 最大值滑块 */}
<View
className={`slider-thumb ${activeThumb === 'max' ? 'active' : ''}`}
style={{ left: `${getSliderPercentage(value.max)}%` }}
onTouchStart={() => handleSliderTouchStart('max')}
>
<View className='thumb-value'>{value.max}</View>
</View>
</View>
</View>
</View>
</View>
)
}
export default NTRPSlider