React + JavaScript 实现可拖拽进度条
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;