2025-10-20 13:06:06 +08:00

67 lines
1.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import React, { useCallback, useRef, useState } from 'react';
type HoverVideoProps = {
videoUrl: string;
coverUrl?: string | null;
className?: string;
style?: React.CSSProperties;
};
/**
* 鼠标移入才加载视频并自动播放,移出暂停并释放资源;默认显示封面。
*/
export default function HoverVideo({ videoUrl, coverUrl, className, style }: HoverVideoProps) {
const [active, setActive] = useState(false);
const videoRef = useRef<HTMLVideoElement | null>(null);
const onEnter = useCallback(() => {
setActive(true);
// 播放在下一帧触发,避免 ref 尚未赋值
requestAnimationFrame(() => {
const v = videoRef.current;
if (!v) return;
v.play().catch(() => {});
});
}, [videoUrl]);
const onLeave = useCallback(() => {
const v = videoRef.current;
if (v) {
try {
v.pause();
v.load();
} catch {}
}
setActive(false);
}, []);
return (
<div className={className} style={style} onMouseEnter={onEnter} onMouseLeave={onLeave}>
{/* 封面始终渲染在底层 */}
<img
src={coverUrl || '/placeholder.svg'}
alt="cover"
className="absolute inset-0 w-full h-full object-cover"
draggable={false}
loading='lazy'
/>
{/* 仅在激活后渲染视频;初始不设置 src防止提前加载 */}
{active ? (
<video
ref={videoRef}
muted
playsInline
loop
autoPlay
src={videoUrl}
preload="none"
className="absolute inset-0 w-full h-full object-cover"
/>
) : null}
</div>
);
}