Time

预计阅读时间: 4 分钟

Time 功能提供对 Video.js 播放器时间状态的完整管理,包括当前时间、时长和跳转操作。

概述

Time 功能是 Video.js React 中用于管理播放时间的模块。它提供当前播放位置、总时长和跳转功能,是构建进度条和时间显示的核心功能。

状态

属性类型描述
currentTimenumber当前播放时间(秒)
durationnumber视频总时长(秒)
seekingboolean是否正在跳转中

状态说明

  • currentTime:当前播放位置的时间,单位为秒
  • duration:视频的总时长,如果未知则为 0
  • seeking:当用户拖动进度条或调用 seek 操作时为 true

操作

操作类型描述
seekAction跳转到指定时间

seek

跳转到视频的指定时间位置。

import { usePlayerActions, usePlayer } from '@videojs/react';
import { selectTime } from '@videojs/react';

function TimeControls() {
  const time = usePlayer(selectTime);
  const { seek } = usePlayerActions();
  
  const formatTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  };
  
  return (
    <div className="time-controls">
      <span>{formatTime(time.currentTime)}</span>
      <span>/</span>
      <span>{formatTime(time.duration)}</span>
    </div>
  );
}

选择器

传递 selectTimeusePlayer 钩子以订阅时间状态。

import { selectTime, usePlayer } from '@videojs/react';

function TimeStatus() {
  const time = usePlayer(selectTime);
  
  return (
    <div>
      <p>当前时间: {time.currentTime}秒</p>
      <p>总时长: {time.duration}秒</p>
      <p>跳转中: {time.seeking ? '是' : '否'}</p>
    </div>
  );
}

示例

进度条

import { selectTime, usePlayer, usePlayerActions } from '@videojs/react';

function ProgressBar() {
  const time = usePlayer(selectTime);
  const { seek } = usePlayerActions();
  
  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const percent = (e.clientX - rect.left) / rect.width;
    const newTime = percent * time.duration;
    seek(newTime);
  };
  
  const progress = time.duration > 0 
    ? (time.currentTime / time.duration) * 100 
    : 0;
  
  return (
    <div className="progress-bar" onClick={handleClick}>
      <div 
        className="progress-fill" 
        style={{ width: `${progress}%` }}
      />
      {time.seeking && <div className="seeking-indicator">跳转中...</div>}
    </div>
  );
}

时间格式化显示

import { selectTime, usePlayer } from '@videojs/react';

function FormattedTime() {
  const time = usePlayer(selectTime);
  
  const formatTime = (seconds: number): string => {
    if (!isFinite(seconds)) return '0:00';
    
    const hours = Math.floor(seconds / 3600);
    const mins = Math.floor((seconds % 3600) / 60);
    const secs = Math.floor(seconds % 60);
    
    if (hours > 0) {
      return `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
    }
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  };
  
  return (
    <div className="time-display">
      <span className="current">{formatTime(time.currentTime)}</span>
      <span className="separator">/</span>
      <span className="duration">{formatTime(time.duration)}</span>
    </div>
  );
}

剩余时间显示

import { selectTime, usePlayer } from '@videojs/react';

function RemainingTime() {
  const time = usePlayer(selectTime);
  
  const remaining = time.duration - time.currentTime;
  
  return (
    <div className="remaining-time">
      剩余: {Math.ceil(remaining)} 秒
    </div>
  );
}

跳转控制按钮

import { selectTime, usePlayer, usePlayerActions } from '@videojs/react';

function SkipControls() {
  const time = usePlayer(selectTime);
  const { seek } = usePlayerActions();
  
  const skip = (seconds: number) => {
    const newTime = Math.max(0, Math.min(time.duration, time.currentTime + seconds));
    seek(newTime);
  };
  
  return (
    <div className="skip-controls">
      <button onClick={() => skip(-10)}>-10秒</button>
      <button onClick={() => skip(-5)}>-5秒</button>
      <button onClick={() => skip(5)}>+5秒</button>
      <button onClick={() => skip(10)}>+10秒</button>
    </div>
  );
}

缓冲进度条

import { selectTime, selectBuffer, usePlayer } from '@videojs/react';

function BufferedProgressBar() {
  const time = usePlayer(selectTime);
  const buffer = usePlayer(selectBuffer);
  
  const progress = time.duration > 0 
    ? (time.currentTime / time.duration) * 100 
    : 0;
  
  // 计算缓冲进度
  const getBufferedProgress = () => {
    if (!buffer.buffered.length || !time.duration) return 0;
    
    // 获取最后一个缓冲范围的结束时间
    const lastRange = buffer.buffered[buffer.buffered.length - 1];
    return (lastRange.end / time.duration) * 100;
  };
  
  const bufferedProgress = getBufferedProgress();
  
  return (
    <div className="progress-bar-container">
      <div className="progress-bar">
        <div 
          className="buffer" 
          style={{ width: `${bufferedProgress}%` }}
        />
        <div 
          className="progress" 
          style={{ width: `${progress}%` }}
        />
      </div>
    </div>
  );
}

注意事项

  1. 时间单位:所有时间值都以秒为单位
  2. 未知时长:直播流或不完整视频的 duration 可能为 0 或 Infinity
  3. 精度问题:浮点数时间可能导致显示不一致
  4. 跳转延迟:跳转操作可能需要时间完成
  5. 边界处理:跳转时间应限制在有效范围内