Toggle navigation
Toggle navigation
This project
Loading...
Sign in
卢阳
/
front_backend_zImage
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
ly0303521
2026-02-02 17:22:03 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
157dc40b4bcc1744482aeb9935a67d36eafbbb72
157dc40b
1 parent
f83d0077
修改页面中缩略图和视频的加载策略,提高加载速度
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
48 additions
and
31 deletions
z-image-generator/components/ImageCard.tsx
z-image-generator/components/ImageCard.tsx
View file @
157dc40
...
...
@@ -12,6 +12,8 @@ interface ImageCardProps {
const ImageCard: React.FC<ImageCardProps> = ({ image, onClick, onLike, currentUser, isVideo = false }) => {
const [isLoaded, setIsLoaded] = useState(false);
const [isHovered, setIsHovered] = useState(false);
const [videoStarted, setVideoStarted] = useState(false);
const videoRef = useRef<HTMLVideoElement>(null);
const handleLike = (e: React.MouseEvent) => {
...
...
@@ -20,60 +22,75 @@ const ImageCard: React.FC<ImageCardProps> = ({ image, onClick, onLike, currentUs
};
const handleMouseEnter = () => {
if (videoRef.current) {
videoRef.current.currentTime = 0;
videoRef.current.play().catch(e => console.error("Video play failed", e));
}
setIsHovered(true);
// Video will be played via autoPlay once rendered
}
const handleMouseLeave = () => {
if (videoRef.current) {
videoRef.current.pause();
videoRef.current.currentTime = videoRef.current.duration || 0;
}
setIsHovered(false);
setVideoStarted(false);
}
const handleVideoMetadata = () => {
if (videoRef.current) {
videoRef.current.currentTime = videoRef.current.duration || 0;
}
}
// If it's a video with a thumbnail, we want to show it immediately (via poster)
// instead of waiting for the video file to load metadata.
// Content is considered "ready" if the main image/video is loaded
// OR if we have a thumbnail to show for a video.
const showContent = isLoaded || (isVideo && !!image.thumbnail);
return (
<div
className="group relative mb-4 break-inside-avoid rounded-2xl overflow-hidden bg-gray-
2
00 cursor-zoom-in shadow-sm hover:shadow-xl transition-all duration-300"
className="group relative mb-4 break-inside-avoid rounded-2xl overflow-hidden bg-gray-
1
00 cursor-zoom-in shadow-sm hover:shadow-xl transition-all duration-300"
onClick={() => onClick(image)}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{/* Placeholder / Skeleton */}
{!showContent && (
<div className="absolute inset-0 bg-gray-200 animate-pulse min-h-[
20
0px]" />
<div className="absolute inset-0 bg-gray-200 animate-pulse min-h-[
15
0px]" />
)}
{/* Main Content */}
{isVideo ? (
<video
ref={videoRef}
src={image.url}
poster={image.thumbnail} // Use thumbnail as poster
className={`w-full h-auto object-cover transition-opacity duration-300 ${showContent ? 'opacity-100' : 'opacity-0'}`}
onLoadedMetadata={handleVideoMetadata}
onLoadedData={() => setIsLoaded(true)}
loop
muted
playsInline
preload="metadata"
/>
<div className="relative w-full overflow-hidden bg-gray-100">
{/* Always show thumbnail first */}
<img
src={image.thumbnail || (isVideo ? '' : image.url)}
alt={image.prompt}
className={`w-full h-auto object-cover transition-opacity duration-500 ${videoStarted ? 'opacity-0' : 'opacity-100'} ${!image.thumbnail && isVideo ? 'opacity-0' : ''}`}
onLoad={() => setIsLoaded(true)}
loading="lazy"
/>
{isVideo && !image.thumbnail && !videoStarted && (
<div className="absolute inset-0 flex items-center justify-center bg-gray-200 text-gray-400">
<Video size={32} />
</div>
)}
{/* Load video only on hover */}
{isHovered && (
<video
ref={videoRef}
src={image.url}
className={`absolute inset-0 w-full h-full object-cover transition-opacity duration-300 ${videoStarted ? 'opacity-100' : 'opacity-0'}`}
onLoadedData={() => setVideoStarted(true)}
autoPlay
loop
muted
playsInline
/>
)}
{/* Video Indicator Icon (When not hovered) */}
{!isHovered && (
<div className="absolute top-3 left-3 p-1.5 bg-black/30 backdrop-blur-md rounded-lg text-white/90">
<Video size={14} />
</div>
)}
</div>
) : (
<img
src={image.url}
alt={image.prompt}
className={`w-full h-auto object-cover transition-transform duration-700 ease-in-out group-hover:scale-105 ${
showContent
? 'opacity-100' : 'opacity-0'}`}
className={`w-full h-auto object-cover transition-transform duration-700 ease-in-out group-hover:scale-105 ${
isLoaded
? 'opacity-100' : 'opacity-0'}`}
onLoad={() => setIsLoaded(true)}
loading="lazy"
/>
...
...
Please
register
or
login
to post a comment