diff --git a/components/home/MaterialCard.test.tsx b/components/home/MaterialCard.test.tsx index c1f5024..01eaf6a 100644 --- a/components/home/MaterialCard.test.tsx +++ b/components/home/MaterialCard.test.tsx @@ -140,6 +140,39 @@ describe('MaterialCard', () => { expect(screen.getByText('15天后可查看详情')).toBeInTheDocument() }) + test('视频卡片初始只加载封面,悬停时才挂载视频预览', () => { + const { container } = render( + , + ) + + const previewArea = container.querySelector('[data-material-link="true"]') + expect(previewArea).not.toBeNull() + expect(screen.getByAltText('SPU-001 视频封面')).toHaveAttribute( + 'src', + 'https://example.com/video-cover.jpg', + ) + expect(screen.queryByLabelText('SPU-001 视频预览')).not.toBeInTheDocument() + + fireEvent.mouseEnter(previewArea!) + expect(screen.getByLabelText('SPU-001 视频预览')).toHaveAttribute( + 'src', + 'https://example.com/video-preview.mp4', + ) + + fireEvent.mouseLeave(previewArea!) + expect(screen.queryByLabelText('SPU-001 视频预览')).not.toBeInTheDocument() + expect(screen.getByAltText('SPU-001 视频封面')).toBeInTheDocument() + }) + test('15天保护期内仍可复制分享链接', () => { render( (null) const [posterLoadError, setPosterLoadError] = useState(false) + const [shouldLoadVideoPreview, setShouldLoadVideoPreview] = useState(false) // 判断素材类型 const isVideoType = isVideoMaterialType(material.materialType) @@ -173,30 +173,11 @@ export default function MaterialCard({ reportTitle: material.reportTitle, }) - // 检测封面图是否可加载 + // 素材切换时回到封面态;视频只在用户悬停时加载,避免列表首屏并发预载全部视频。 useEffect(() => { - if (isVideoType && posterUrl && typeof window !== 'undefined') { - setPosterLoadError(false) - const img = document.createElement('img') - img.onload = () => { - setPosterLoadError(false) - } - img.onerror = () => { - console.error('[MaterialCard] 视频封面图预加载失败:', { - materialId: material.id, - productModel: materialDisplayTitle, - videoCoverUrl: material.videoCoverUrl, - previewUrl: material.previewUrl, - posterUrl: posterUrl, - timestamp: new Date().toISOString() - }) - setPosterLoadError(true) - } - img.src = posterUrl - } else { - setPosterLoadError(false) - } - }, [isVideoType, posterUrl, material.id, materialDisplayTitle, material.videoCoverUrl, material.previewUrl]) + setPosterLoadError(false) + setShouldLoadVideoPreview(false) + }, [material.id, posterUrl]) // 音频URL(API已经处理过,直接使用) let audioUrl = '' @@ -218,18 +199,13 @@ export default function MaterialCard({ onClick(material) } - // 视频鼠标悬停播放控制 + // 视频鼠标悬停播放控制:离开后卸载 video,立即释放媒体连接。 const handleVideoMouseEnter = () => { - if (videoRef.current) { - videoRef.current.play().catch(() => {}) - } + setShouldLoadVideoPreview(true) } const handleVideoMouseLeave = () => { - if (videoRef.current) { - videoRef.current.pause() - videoRef.current.currentTime = 0 - } + setShouldLoadVideoPreview(false) } // 复制ID到剪贴板 @@ -376,28 +352,43 @@ export default function MaterialCard({ {/* 视频类型 */} {isVideoType && videoPreviewUrl ? ( <> -