t10015/components/products/ProductImageGallery.jsx

109 lines
4.1 KiB
JavaScript
Raw 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 { useState, useEffect } from 'react';
const ProductImageGallery = ({ data }) => {
const [currentImageIndex, setCurrentImageIndex] = useState(0);
// 如果没有attachments不显示组件
if (!data?.attachments || data.attachments.length === 0) {
return null;
}
// 找到主图在attachments中的索引
const getMainImageIndex = () => {
if (!data.image) return 0;
const mainImageIndex = data.attachments.findIndex(
attachment => attachment.file_url === data.image
);
return mainImageIndex >= 0 ? mainImageIndex : 0;
};
const mainImageIndex = getMainImageIndex();
const currentImage = data.attachments[currentImageIndex]?.file_url || data.attachments[0]?.file_url;
// 初始化当前索引为主图索引
useEffect(() => {
setCurrentImageIndex(mainImageIndex);
}, [mainImageIndex]);
const changeMainImage = (direction) => {
if (data.attachments.length <= 1) return;
if (direction === 'next') {
setCurrentImageIndex((prev) => (prev + 1) % data.attachments.length);
} else {
setCurrentImageIndex((prev) => (prev - 1 + data.attachments.length) % data.attachments.length);
}
};
const changeMainImageByIndex = (index) => {
setCurrentImageIndex(index);
};
return (
<div className="flex-shrink-0 w-full md:w-120 flex justify-center md:justify-start mb-4 md:mb-0 max-w-full">
<div className="relative w-full max-w-[320px] md:max-w-full">
{/* 主图显示区域 */}
<div className="relative overflow-hidden rounded-xl shadow-lg mb-4">
<img
src={currentImage}
alt={data?.title || 'Product Image'}
className="w-full max-w-[320px] md:max-w-full object-contain"
/>
{/* 导航箭头 */}
{data.attachments.length > 1 && (
<>
<button
className="absolute left-2 top-1/2 transform -translate-y-1/2 w-8 h-8 bg-white rounded-full border border-gray-300 flex items-center justify-center shadow-md hover:bg-gray-50 transition-colors z-10"
onClick={() => changeMainImage('prev')}
aria-label="Previous image"
>
<svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
</button>
<button
className="absolute right-2 top-1/2 transform -translate-y-1/2 w-8 h-8 bg-white rounded-full border border-gray-300 flex items-center justify-center shadow-md hover:bg-gray-50 transition-colors z-10"
onClick={() => changeMainImage('next')}
aria-label="Next image"
>
<svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
</>
)}
</div>
{/* 缩略图列表 - 直接显示attachments */}
<div className="flex flex-wrap gap-1 justify-center md:justify-start">
{data.attachments.map((attachment, index) => (
<div
key={index}
className={`w-16 h-16 border-1 rounded-lg overflow-hidden cursor-pointer transition-all hover:border-blue-500 ${
index === currentImageIndex ? 'border-blue-500' : 'border-gray-200'
}`}
onClick={() => changeMainImageByIndex(index)}
>
<img
src={attachment.file_url}
alt={`${data?.title || 'Product'} - ${index + 1}`}
className="w-full h-full object-cover"
onError={(e) => {
console.error('Image load error:', attachment.file_url);
e.target.style.display = 'none';
}}
/>
</div>
))}
</div>
</div>
</div>
);
};
export default ProductImageGallery;