You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中Video.js初始化设置currentTime导致GCS视频无法显示

问题:Video.js封装GCS公开视频设置起始时间后视频无法显示

我正在React项目中用Video.js封装Google Cloud Storage(GCS)的公开视频URL,目的是自定义播放器外观并控制视频的起始播放时间(比如从第12秒开始播放)。但设置currentTime后视频完全无法显示,只有播放器控件可见。通过注释代码排查,确认是const player = videojs(videoElement);这一行导致了问题。

我的React组件中useEffect代码如下:

useEffect(() => {
  results.forEach((result, index) => {
    if (result.metadata.file_type === 'video') {
      const videoElement = document.getElementById(`video-${index}`);
      if (videoElement) {
        const player = videojs(videoElement);
        player.ready(() => {
          player.src({ type: 'video/mp4', src: result.metadata.gcs_public_url });
          player.currentTime(result.metadata.start_offset_sec); // 设置起始播放时间
        });
      }
    }
  });
}, [results]);

循环渲染视频的HTML代码(GCS公开URL格式为https://storage.googleapis.com/project/folder/video.mp4):

{results.map((result, index) => (
  <video
    id={`video-${index}`}
    className="video-js vjs-default w-full h-auto mt-2"
    controls
    muted
    preload="auto"
  >
    <source src={result.metadata.gcs_public_url} type="video/mp4" />
    Your browser does not support the video tag.
  </video>
))}

解决方案

1. 避免重复初始化播放器实例

React的useEffect会在results变化时重新执行,多次调用videojs()初始化同一个video元素会导致实例冲突,引发渲染异常。可以用useRef存储已初始化的播放器,避免重复创建:

import { useEffect, useRef } from 'react';

// 在组件内定义ref存储播放器实例
const playersRef = useRef<Record<number, videojs.Player>>({});

useEffect(() => {
  results.forEach((result, index) => {
    if (result.metadata.file_type === 'video') {
      const videoElement = document.getElementById(`video-${index}`);
      if (videoElement && !playersRef.current[index]) {
        // 仅当未初始化过该播放器时才创建实例
        const player = videojs(videoElement);
        playersRef.current[index] = player;

        player.ready(() => {
          player.src({ type: 'video/mp4', src: result.metadata.gcs_public_url });
        });

        // 监听视频元数据加载完成事件,再设置起始时间
        player.on('loadedmetadata', () => {
          player.currentTime(result.metadata.start_offset_sec);
        });
      }
    }
  });

  // 组件卸载时销毁播放器实例,避免内存泄漏
  return () => {
    Object.values(playersRef.current).forEach(player => player.dispose());
    playersRef.current = {};
  };
}, [results]);

2. 移除原生video标签中的<source>

因为已经通过Video.js的player.src()方法设置了视频源,原生的<source>标签会导致视频被加载两次,引发冲突。修改HTML部分:

{results.map((result, index) => (
  <video
    key={index}
    id={`video-${index}`}
    className="video-js vjs-default w-full h-auto mt-2"
    controls
    muted
    preload="auto"
  >
    Your browser does not support the video tag.
  </video>
))}

3. 确保Video.js样式正确引入

如果播放器控件显示但视频区域空白,还要确认是否正确引入了Video.js的CSS样式,比如在项目中添加:

import 'video.js/dist/video-js.css';

内容的提问来源于stack exchange,提问作者theGreenCabbage

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 01:23:16