React + JavaScript 实现可拖拽进度条
下面是一个使用 React (JavaScript) 实现的可拖拽时间进度条组件。
代码
js
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;
CSS 样式
css
.time-progress-container {
width: 100%;
max-width: 600px;
margin: 0 auto;
padding: 10px 0;
}
.progress-bar {
position: relative;
height: 8px;
background-color: #e0e0e0;
border-radius: 4px;
cursor: pointer;
margin-bottom: 10px;
}
.progress-fill {
position: absolute;
height: 100%;
background-color: #4285f4;
border-radius: 4px;
transition: width 0.1s ease;
}
.progress-thumb {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 16px;
height: 16px;
background-color: #4285f4;
border-radius: 50%;
cursor: grab;
z-index: 2;
transition: left 0.1s ease;
}
.progress-thumb:active {
cursor: grabbing;
}
.time-display {
display: flex;
justify-content: space-between;
font-size: 14px;
color: #666;
}
使用
js
import React from 'react';
import TimeProgressBar from './TimeProgressBar';
function App() {
const handleTimeChange = (time) => {
console.log('当前时间:', time);
};
return (
<div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
<h2>视频播放器</h2>
<TimeProgressBar
totalTime={720} // 12分钟
initialTime={120} // 从2分钟开始
onChange={handleTimeChange}
/>
</div>
);
}
export default App;
功能特点
- 完全可拖拽:可以通过鼠标或触摸拖动滑块
- 点击跳转:点击进度条任意位置可跳转到对应时间点
- 响应式设计:适应不同屏幕尺寸
- 平滑过渡:添加了CSS过渡效果
- 触摸支持:支持移动设备触摸操作
- 时间显示:显示当前时间和总时间
- 回调函数:提供onChange回调,当时间变化时触发
自定义选项
你可以通过以下props自定义组件:
totalTime
: 设置总时间(秒)initialTime
: 设置初始时间(秒)onChange
: 时间变化时的回调函数
