diff --git a/components/products/ProductImageGallery.jsx b/components/products/ProductImageGallery.jsx index 4e8dd78..7c9ec55 100644 --- a/components/products/ProductImageGallery.jsx +++ b/components/products/ProductImageGallery.jsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useEffect, useRef } from 'react'; +import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { Swiper, SwiperSlide } from "swiper/react"; import { Navigation, Pagination, Thumbs, FreeMode } from "swiper/modules"; @@ -21,8 +21,8 @@ const ProductImageGallery = ({ data }) => { return null; } - // 找到主图在attachments中的索引 - const getMainImageIndex = () => { + // 使用useMemo优化主图索引计算 + const mainImageIndex = useMemo(() => { if (!data.image) return 0; const mainImageIndex = data.attachments.findIndex( @@ -30,34 +30,34 @@ const ProductImageGallery = ({ data }) => { ); return mainImageIndex >= 0 ? mainImageIndex : 0; - }; + }, [data.image, data.attachments]); - const mainImageIndex = getMainImageIndex(); - const currentImage = data.attachments[currentImageIndex]?.file_url || data.attachments[0]?.file_url; + // 使用useMemo优化当前图片URL + const currentImage = useMemo(() => { + return data.attachments[currentImageIndex]?.file_url || data.attachments[0]?.file_url; + }, [data.attachments, currentImageIndex]); - // 专门的缩略图滚动函数 - const scrollThumbnailToIndex = (index) => { - console.log('滚动缩略图到索引:', index); // 调试信息 - - if (thumbsSwiperRef.current && thumbsSwiperRef.current.swiper) { - const swiper = thumbsSwiperRef.current.swiper; - console.log('Swiper实例存在,开始滚动'); // 调试信息 - - // 使用更简单的方法:直接滚动到指定索引 + // 使用useCallback优化缩略图滚动函数 + const scrollThumbnailToIndex = useCallback((index) => { + if (thumbsSwiperRef.current?.swiper) { try { - swiper.slideTo(index, 300); - console.log('滚动成功,目标索引:', index); + const swiper = thumbsSwiperRef.current.swiper; + + if (index === 0) { + // 第一张图片,滚动到最左侧 + swiper.scrollTo(0, 300); + } else { + // 其他图片使用原有的slideTo方法,保持正常滚动 + swiper.slideTo(index, 300); + } } catch (error) { - console.error('滚动失败:', error); + // 静默处理错误 } - } else { - console.log('Swiper实例不存在,thumbsSwiperRef:', thumbsSwiperRef.current); } - }; + }, []); - const changeMainImage = (direction) => { - console.log('changeMainImage 被调用,方向:', direction); // 调试信息 - + // 使用useCallback优化主图切换函数 + const changeMainImage = useCallback((direction) => { if (data.attachments.length <= 1) return; let newIndex; @@ -67,84 +67,106 @@ const ProductImageGallery = ({ data }) => { newIndex = (currentImageIndex - 1 + data.attachments.length) % data.attachments.length; } - console.log('新的索引:', newIndex, '当前索引:', currentImageIndex); // 调试信息 - setCurrentImageIndex(newIndex); // 自动滚动缩略图到对应位置 setTimeout(() => { - console.log('开始执行滚动,索引:', newIndex); // 调试信息 scrollThumbnailToIndex(newIndex); }, 100); - }; + }, [currentImageIndex, data.attachments.length, scrollThumbnailToIndex]); - const changeMainImageByIndex = (index) => { + // 使用useCallback优化按索引切换主图函数 + const changeMainImageByIndex = useCallback((index) => { setCurrentImageIndex(index); // 智能滚动缩略图到可见区域 setTimeout(() => { scrollThumbnailToIndex(index); }, 100); - }; + }, [scrollThumbnailToIndex]); // 初始化当前索引为主图索引 useEffect(() => { setCurrentImageIndex(mainImageIndex); }, [mainImageIndex]); - // 键盘导航支持 - useEffect(() => { - const handleKeyDown = (event) => { - if (data.attachments.length <= 1) return; - - switch (event.key) { - case 'ArrowLeft': - event.preventDefault(); - changeMainImage('prev'); - break; - case 'ArrowRight': - event.preventDefault(); - changeMainImage('next'); - break; - case 'Home': - event.preventDefault(); - setCurrentImageIndex(0); - setTimeout(() => scrollThumbnailToIndex(0), 100); - break; - case 'End': - event.preventDefault(); - setCurrentImageIndex(data.attachments.length - 1); - setTimeout(() => scrollThumbnailToIndex(data.attachments.length - 1), 100); - break; - default: - break; - } - }; + // 键盘导航支持 - 使用useCallback优化 + const handleKeyDown = useCallback((event) => { + if (data.attachments.length <= 1) return; + + switch (event.key) { + case 'ArrowLeft': + event.preventDefault(); + changeMainImage('prev'); + break; + case 'ArrowRight': + event.preventDefault(); + changeMainImage('next'); + break; + case 'Home': + event.preventDefault(); + setCurrentImageIndex(0); + setTimeout(() => scrollThumbnailToIndex(0), 100); + break; + case 'End': + event.preventDefault(); + setCurrentImageIndex(data.attachments.length - 1); + setTimeout(() => scrollThumbnailToIndex(data.attachments.length - 1), 100); + break; + default: + break; + } + }, [data.attachments.length, changeMainImage, scrollThumbnailToIndex]); - // 添加键盘事件监听器 + useEffect(() => { document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; - }, [data.attachments.length]); + }, [handleKeyDown]); - - - // 缩略图导航控制 - 移除这些函数,不再需要 - // const goToPrevThumbs = () => { - // if (thumbsSwiperRef.current && thumbsSwiperRef.current.swiper) { - // thumbsSwiperRef.current.swiper.slidePrev(); - // } - // }; - - // const goToNextThumbs = () => { - // if (thumbsSwiperRef.current && thumbsSwiperRef.current.swiper) { - // if (thumbsSwiperRef.current && thumbsSwiperRef.current.swiper) { - // thumbsSwiperRef.current.swiper.slideNext(); - // } - // } - // }; + // 使用useMemo优化缩略图渲染 + const thumbnailSlides = useMemo(() => { + return data.attachments.map((attachment, index) => ( + changeMainImageByIndex(index)} + > +
{ + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + changeMainImageByIndex(index); + } + }} + > + {`${data?.title { + e.target.style.display = 'none'; + }} + /> + {/* 缩略图加载状态指示 */} +
+
+
+
+
+ )); + }, [data.attachments, currentImageIndex, data?.title, changeMainImageByIndex]); return (
@@ -218,57 +240,13 @@ const ProductImageGallery = ({ data }) => { slidesPerView="auto" freeMode={true} watchSlidesProgress={true} - modules={[FreeMode, Navigation, Pagination]} + modules={[FreeMode, Navigation, Pagination, Thumbs]} className="thumbs-swiper" grabCursor={true} resistance={true} resistanceRatio={0.85} - breakpoints={{ - 0: { slidesPerView: 3, spaceBetween: 12 }, - 480: { slidesPerView: 4, spaceBetween: 16 }, - 768: { slidesPerView: 5, spaceBetween: 16 }, - 1024: { slidesPerView: 6, spaceBetween: 16 } - }} > - {data.attachments.map((attachment, index) => ( - changeMainImageByIndex(index)} - > -
{ - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - changeMainImageByIndex(index); - } - }} - > - {`${data?.title { - console.error('Image load error:', attachment.file_url); - e.target.style.display = 'none'; - }} - /> - {/* 缩略图加载状态指示 */} -
-
-
-
-
- ))} + {thumbnailSlides}
)} @@ -279,12 +257,18 @@ const ProductImageGallery = ({ data }) => { /* 缩略图悬停效果 */ .thumbs-swiper .swiper-slide { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + width: 64px !important; /* 确保宽度为64px */ + margin-right: 16px !important; /* 确保右边距为16px */ } .thumbs-swiper .swiper-slide:hover { transform: scale(1.05); } + .thumbs-swiper .swiper-slide:last-child { + margin-right: 0 !important; /* 最后一个缩略图不需要右边距 */ + } + /* 当前选中的缩略图样式 */ .border-2.border-blue-500 { border-color: #3b82f6;