React + JavaScript 实现可拖拽进度条

发布于:2025-04-16 ⋅ 阅读:(36) ⋅ 点赞:(0)

React + JavaScript 实现可拖拽进度条

下面是一个使用 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;
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;
}
使用
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;
功能特点
  1. 完全可拖拽:可以通过鼠标或触摸拖动滑块
  2. 点击跳转:点击进度条任意位置可跳转到对应时间点
  3. 响应式设计:适应不同屏幕尺寸
  4. 平滑过渡:添加了CSS过渡效果
  5. 触摸支持:支持移动设备触摸操作
  6. 时间显示:显示当前时间和总时间
  7. 回调函数:提供onChange回调,当时间变化时触发
自定义选项

你可以通过以下props自定义组件:

  • totalTime: 设置总时间(秒)
  • initialTime: 设置初始时间(秒)
  • onChange: 时间变化时的回调函数

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到