React + JavaScript 实现可拖拽进度条

时间:2025-04-16 12:02:40
import React, { useState, useRef, useEffect } from 'react'; import './TimeProgressBar.css'; const TimeProgressBar = ({ totalTime = 600, // 默认10分钟 (600秒) initialTime = 0, onChange, }) => { const [currentTime, setCurrentTime] = useState(initialTime); const [isDragging, setIsDragging] = useState(false); const progressBarRef = useRef(null); // 格式化时间 (秒 → HH:MM:SS) const formatTime = (seconds) => { const hrs = Math.floor(seconds / 3600); const mins = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); return [ hrs.toString().padStart(2, '0'), mins.toString().padStart(2, '0'), secs.toString().padStart(2, '0') ].join(':'); }; // 计算进度百分比 const getPercentage = () => { return Math.min((currentTime / totalTime) * 100, 100); }; // 更新进度 const updateProgress = (time) => { const newTime = Math.max(0, Math.min(time, totalTime)); setCurrentTime(newTime); if (onChange) onChange(newTime); }; // 处理进度条点击 const handleProgressBarClick = (e) => { if (progressBarRef.current) { const rect = progressBarRef.current.getBoundingClientRect(); const pos = (e.clientX - rect.left) / rect.width; updateProgress(pos * totalTime); } }; // 处理拖拽开始 const handleDragStart = (e) => { setIsDragging(true); e.preventDefault(); }; // 处理拖拽移动 const handleDragMove = (e) => { if (!isDragging || !progressBarRef.current) return; const rect = progressBarRef.current.getBoundingClientRect(); const pos = (e.clientX - rect.left) / rect.width; updateProgress(pos * totalTime); }; // 处理拖拽结束 const handleDragEnd = () => { setIsDragging(false); }; // 添加/移除事件监听器 useEffect(() => { document.addEventListener('mousemove', handleDragMove); document.addEventListener('mouseup', handleDragEnd); document.addEventListener('touchmove', handleDragMove); document.addEventListener('touchend', handleDragEnd); return () => { document.removeEventListener('mousemove', handleDragMove); document.removeEventListener('mouseup', handleDragEnd); document.removeEventListener('touchmove', handleDragMove); document.removeEventListener('touchend', handleDragEnd); }; }, [isDragging]); return ( <div className="time-progress-container"> <div className="progress-bar" ref={progressBarRef} onClick={handleProgressBarClick} > <div className="progress-fill" style={{ width: `${getPercentage()}%` }} /> <div className="progress-thumb" style={{ left: `${getPercentage()}%` }} onMouseDown={handleDragStart} onTouchStart={handleDragStart} /> </div> <div className="time-display"> <span className="current-time">{formatTime(currentTime)}</span> <span className="total-time">{formatTime(totalTime)}</span> </div> </div> ); }; export default TimeProgressBar;