如何在渲染布局前获取视频高度,解决标签页切换布局抖动问题
解决标签页切换时视频播放器导致的布局抖动问题
布局抖动的根源是视频加载完成前高度为0,加载后高度突变引发下方元素移位;你之前的代码只在组件挂载时获取高度,此时视频元数据尚未加载,所以高度为0。以下是可行的解决方案:
1. 监听视频元数据加载事件获取准确高度
视频的loadedmetadata事件会在视频的宽高、时长等元数据加载完成后触发,此时获取的高度才是准确的:
import { useState, useRef, useEffect } from 'react'; import CardMedia from '@mui/material/CardMedia'; // ...组件内部代码 const [videoHeight, setVideoHeight] = useState<number | null>(null); const videoElement = useRef<HTMLVideoElement>(null); useEffect(() => { const video = videoElement.current; if (!video) return; // 视频元数据加载完成后计算高度 const handleMetadataLoaded = () => { // 获取视频容器的宽度,结合视频宽高比计算适配高度 const containerWidth = video.parentElement?.clientWidth || video.clientWidth; const aspectRatio = video.videoWidth / video.videoHeight; const calculatedHeight = containerWidth / aspectRatio; setVideoHeight(calculatedHeight); }; // 监听标签页切换(视频从隐藏转为显示)的情况 const handleVisibilityChange = () => { if (!document.hidden && video) { const containerWidth = video.parentElement?.clientWidth || video.clientWidth; const aspectRatio = video.videoWidth / video.videoHeight; setVideoHeight(containerWidth / aspectRatio); } }; video.addEventListener('loadedmetadata', handleMetadataLoaded); document.addEventListener('visibilitychange', handleVisibilityChange); // 清理事件监听 return () => { video.removeEventListener('loadedmetadata', handleMetadataLoaded); document.removeEventListener('visibilitychange', handleVisibilityChange); }; }, [videourl]); // 依赖视频地址,地址变化时重新监听
2. 预先设置占位高度避免加载前抖动
给视频容器设置基于宽高比的占位样式(比如常见的16:9视频,padding-top设为56.25%),确保视频加载前容器有固定高度:
<div style={{ position: 'relative', width: '100%', minHeight: videoHeight || '200px', // 兜底最小高度 paddingTop: videoHeight ? 'unset' : '56.25%' // 未加载时用16:9占位 }}> <CardMedia component={'video'} src={videourl} ref={videoElement} style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} controls /> </div>
3. 标签页切换时强制更新高度
如果使用的是Material UI的Tabs组件,可以在切换标签页的回调中重新计算视频高度:
const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => { setActiveTab(newValue); // 切换到包含视频的标签页时重新计算高度 if (newValue === 0) { // 假设0是视频所在标签页索引 const video = videoElement.current; if (video) { const containerWidth = video.parentElement?.clientWidth || video.clientWidth; const aspectRatio = video.videoWidth / video.videoHeight; setVideoHeight(containerWidth / aspectRatio); } } };
通过以上步骤,既能在视频加载完成后获取准确高度,又能在标签页切换时保证布局稳定,彻底解决抖动问题。
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

