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

React视频画廊:点击播放后控件不显示、播放按钮未隐藏问题

多视频画廊播放控件问题修复

问题核心原因

你的代码存在几个关键问题导致UI未按预期更新:

  • 直接修改showControls数组元素(showControls[index] = true),未通过setShowControls更新状态,React无法感知变化触发重渲染。
  • video标签的controls属性使用字符串值,而它是布尔属性,只要属性存在就会生效,必须传入布尔值才能正确控制显示。
  • vidRef的赋值方式错误,使用push会导致每次渲染都向数组重复添加元素,造成引用混乱。
  • 未实现"同一时间仅播放一个视频"的逻辑,没有暂停其他正在播放的视频并隐藏它们的控件。

修复后的完整代码

import { useState, useRef, useEffect } from 'react';
import { BsPlayCircle } from 'react-icons/bs';

export default function VideoGallery({ videoData }) {
  const [showControls, setShowControls] = useState(
    Array(videoData.length).fill(false)
  );
  const vidRef = useRef([]);

  // 视频数据更新时重置所有控件状态与播放状态
  useEffect(() => {
    setShowControls(Array(videoData.length).fill(false));
    vidRef.current.forEach(vid => vid?.pause());
  }, [videoData]);

  const playVideo = (index) => {
    // 暂停所有其他视频
    vidRef.current.forEach((vid, idx) => {
      if (idx !== index) vid?.pause();
    });

    // 更新控件状态:仅当前视频显示控件,其余隐藏
    setShowControls(prevState => {
      const newState = [...prevState];
      newState.fill(false);
      newState[index] = true;
      return newState;
    });

    // 播放当前视频
    vidRef.current[index]?.play();
  };

  return (
    <div className="relative w-full p-1 group">
      <div className="flex flex-wrap -m-1 md:-m-2">
        {videoData.map((data, index) => {
          return (
            <div
              key={data.videoURL}
              className="relative flex w-full md:w-1/3 sm:w-1/2 flex-wrap group"
            >
              <div className="relative w-full p-1 group">
                {data.videoURL && (
                  <video
                    src={data.videoURL}
                    preload="metadata"
                    controls={showControls[index]} // 用布尔值控制控件显示
                    controlsList="nodownload"
                    ref={(el) => vidRef.current[index] = el} // 按索引直接赋值,避免重复添加
                  />
                )}
                <div className="absolute top-1/2 left-1/2 -translate-y-1/2 -translate-x-1/2">
                  <BsPlayCircle
                    className={`text-[#fa9204] text-6xl cursor-pointer ${showControls[index] ? 'hidden' : ''}`}
                    onClick={() => playVideo(index)}
                  />
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

关键修改说明

  • 状态更新规范:使用setShowControls的函数式更新,基于前一次状态创建新数组,确保React能检测到状态变化并触发重渲染。
  • 控件属性修正:将controls属性改为布尔值showControls[index],符合HTML布尔属性的工作逻辑。
  • 视频引用优化:直接通过索引给vidRef.current[index]赋值,避免重复添加元素导致的引用错误。
  • 单视频播放逻辑:播放当前视频前,遍历所有视频暂停其他视频,并将它们的控件状态设为false,确保同一时间只有一个视频处于播放状态并显示控件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 21:12:50