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 ? (
<>
-