React视频适配容器+圆角实现问题及JS方案异常排查
解决方案:动态适配视频容器并解决videoWidth/videoHeight为0的问题
核心问题分析
你遇到的videoWidth/videoHeight始终为0的原因是:视频元数据尚未加载完成时就执行了尺寸计算逻辑;同时当前代码没有监听视频流的动态尺寸变化(比如getUserMedia的流分辨率调整),也没处理容器尺寸变化的场景。
修正后的代码实现
const DisplayVideo = ({ videoSrc = null, // other props }) => { const videoRef = useRef(null); const borderRef = useRef(null); const [fillMode, setFillMode] = useState(''); // fill-width or fill-height // 计算并设置填充模式的核心函数 const updateFillMode = () => { const video = videoRef.current; const border = borderRef.current; if (!video || !border) return; // 确保视频元数据已加载,避免width/height为0 if (video.videoWidth === 0 || video.videoHeight === 0) return; const vAspectRatio = video.videoWidth / video.videoHeight; const bAspectRatio = border.clientWidth / border.clientHeight; setFillMode(vAspectRatio > bAspectRatio ? 'fill-width' : 'fill-height'); }; useEffect(() => { const video = videoRef.current; if (!video || !videoSrc) return; // 更新视频源 if (video.srcObject !== videoSrc) { video.srcObject = videoSrc; } // 监听视频元数据加载完成事件 video.addEventListener('loadedmetadata', updateFillMode); // 监听视频流尺寸变化事件(适配getUserMedia动态分辨率) video.addEventListener('resize', updateFillMode); // 监听窗口resize,处理容器尺寸变化 window.addEventListener('resize', updateFillMode); video.play(); // 组件卸载时移除监听 return () => { video.removeEventListener('loadedmetadata', updateFillMode); video.removeEventListener('resize', updateFillMode); window.removeEventListener('resize', updateFillMode); }; }, [videoSrc]); // 额外监听容器尺寸变化(如果容器尺寸可能通过非窗口resize改变) useEffect(() => { const border = borderRef.current; if (!border) return; // 使用ResizeObserver监听容器尺寸变化 const resizeObserver = new ResizeObserver(updateFillMode); resizeObserver.observe(border); return () => { resizeObserver.unobserve(border); }; }, []); return ( <div className="display-video-wrapper" ref={borderRef}> <video className={`display-video ${fillMode}`} ref={videoRef} /> {/* other stuff */} </div> ); }; const mapStateToProps = (state, ownProps) => { // stuff return { videoSrc: remoteVideoSrcs[mid] }; }; export default connect(mapStateToProps)(DisplayVideo);
关键修改点说明
- 提取
updateFillMode独立函数,复用尺寸计算逻辑 - 监听视频的
loadedmetadata事件:确保视频元数据加载完成后再获取videoWidth/videoHeight - 监听视频的
resize事件:适配getUserMedia流的动态分辨率变化(比如摄像头切换、网络带宽调整导致的分辨率缩放) - 使用
ResizeObserver监听容器尺寸变化:覆盖容器通过非窗口resize改变尺寸的场景(比如父元素布局变化) - 清理事件监听:避免组件卸载后内存泄漏
- 优化useEffect依赖:仅在
videoSrc变化时重新绑定视频相关监听
配套CSS示例
确保你的CSS能配合fillMode生效:
.display-video-wrapper { border-radius: 12px; overflow: hidden; /* 关键:确保视频圆角生效 */ position: relative; width: 100%; height: 100%; } .display-video { display: block; object-fit: cover; /* 配合fillMode,确保视频填满容器且保持比例 */ } .display-video.fill-width { width: 100%; height: auto; } .display-video.fill-height { height: 100%; width: auto; }
内容的提问来源于stack exchange,提问作者Darren Chiang
相关产品推荐
相关产品推荐

