React切换自定义播放器与Video.js时出现removeChild错误求助
React切换自定义播放器与Video.js时removeChild错误的解决办法
错误原因
当你初始化Video.js实例时,它会把原<video>元素从DOM里移除,替换成自己生成的容器结构。而你的代码里两个播放器共用同一个videoRef,且用了不同的key做条件渲染——切换回自定义播放器时,React会尝试移除已经被Video.js挪走的原<video>节点,DOM节点归属混乱就触发了Failed to execute 'removeChild' on 'Node'错误。
修复步骤
1. 给两个播放器分配独立的ref
别再共用一个videoRef,分开追踪自定义播放器和Video.js的视频节点:
const customVideoRef = useRef(null); const vjsVideoRef = useRef(null); const playerRef = useRef(null); const [isCustomPlayer, setIsCustomPlayer] = useState(true);
2. 条件渲染时绑定对应ref
把两个ref分别绑到各自的<video>组件上,同时给它们不同的id避免冲突:
<div style={{ position: "relative" }}> {isCustomPlayer ? ( // 自定义播放器 <video key="custom-player" id="custom-video-player" className={isShortVideo ? "short-video-container" : "video-container"} ref={customVideoRef} src={videoData?.video_link} controls controlslist="nodownload" disablePictureInPicture ></video> ) : ( // Video.js播放器 <video key="video-js-player" id="vjs-video-player" ref={vjsVideoRef} className={`video-js vjs-default-skin vjs-big-play-centered ${ isShortVideo ? "short-video-container" : "video-container" }`} controls ></video> )} <canvas ref={canvasRef} style={{ display: "none" }} /> <button className="btn btn-toggle-player" onClick={handleTogglePlayer}> 切换到{isCustomPlayer ? "Video.js" : "自定义"}播放器 </button> </div>
3. 修正useEffect逻辑
根据当前播放器类型,操作对应的ref,确保Video.js实例销毁干净:
useEffect(() => { if (isCustomPlayer) { // 切回自定义播放器时,销毁Video.js实例 if (playerRef.current) { playerRef.current.dispose(); playerRef.current = null; } // 可选:如果视频链接变化,重新加载自定义播放器 if (customVideoRef.current && videoData?.video_link) { customVideoRef.current.src = videoData.video_link; customVideoRef.current.load(); } } else { // 切换到Video.js时,初始化实例 if (!playerRef.current && vjsVideoRef.current && videoData?.video_link) { playerRef.current = videojs(vjsVideoRef.current, { controls: true, autoplay: false, preload: "auto", sources: [{ src: videoData.video_link, type: 'video/mp4' }] }); } } // 组件卸载时清理Video.js实例 return () => { if (playerRef.current) { playerRef.current.dispose(); playerRef.current = null; } }; }, [isCustomPlayer, videoData]);
为什么之前的尝试没解决?
- 共用ref导致React和Video.js对同一个DOM节点的操作不同步,节点已经被Video.js移走,React还在尝试操作它;
- 虽然调用了
dispose(),但React的DOM更新机制和Video.js的DOM篡改逻辑冲突,节点归属关系没理清楚。
内容的提问来源于stack exchange,提问作者Zephyr Sonic
相关产品推荐
相关产品推荐

