删除产品详情页注释
This commit is contained in:
parent
fb612d1f3f
commit
e55b8378f1
@ -4,7 +4,6 @@ import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
|||||||
import { Swiper, SwiperSlide } from "swiper/react";
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
import { Navigation, Pagination, Thumbs, FreeMode } from "swiper/modules";
|
import { Navigation, Pagination, Thumbs, FreeMode } from "swiper/modules";
|
||||||
|
|
||||||
// 导入Swiper样式
|
|
||||||
import "swiper/css";
|
import "swiper/css";
|
||||||
import "swiper/css/navigation";
|
import "swiper/css/navigation";
|
||||||
import "swiper/css/pagination";
|
import "swiper/css/pagination";
|
||||||
@ -16,12 +15,10 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
const [thumbsSwiper, setThumbsSwiper] = useState(null);
|
const [thumbsSwiper, setThumbsSwiper] = useState(null);
|
||||||
const thumbsSwiperRef = useRef(null);
|
const thumbsSwiperRef = useRef(null);
|
||||||
|
|
||||||
// 如果没有attachments,不显示组件
|
|
||||||
if (!data?.attachments || data.attachments.length === 0) {
|
if (!data?.attachments || data.attachments.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用useMemo优化主图索引计算
|
|
||||||
const mainImageIndex = useMemo(() => {
|
const mainImageIndex = useMemo(() => {
|
||||||
if (!data.image) return 0;
|
if (!data.image) return 0;
|
||||||
|
|
||||||
@ -32,31 +29,25 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
return mainImageIndex >= 0 ? mainImageIndex : 0;
|
return mainImageIndex >= 0 ? mainImageIndex : 0;
|
||||||
}, [data.image, data.attachments]);
|
}, [data.image, data.attachments]);
|
||||||
|
|
||||||
// 使用useMemo优化当前图片URL
|
|
||||||
const currentImage = useMemo(() => {
|
const currentImage = useMemo(() => {
|
||||||
return data.attachments[currentImageIndex]?.file_url || data.attachments[0]?.file_url;
|
return data.attachments[currentImageIndex]?.file_url || data.attachments[0]?.file_url;
|
||||||
}, [data.attachments, currentImageIndex]);
|
}, [data.attachments, currentImageIndex]);
|
||||||
|
|
||||||
// 使用useCallback优化缩略图滚动函数
|
|
||||||
const scrollThumbnailToIndex = useCallback((index) => {
|
const scrollThumbnailToIndex = useCallback((index) => {
|
||||||
if (thumbsSwiperRef.current?.swiper) {
|
if (thumbsSwiperRef.current?.swiper) {
|
||||||
try {
|
try {
|
||||||
const swiper = thumbsSwiperRef.current.swiper;
|
const swiper = thumbsSwiperRef.current.swiper;
|
||||||
|
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
// 第一张图片,滚动到最左侧
|
|
||||||
swiper.scrollTo(0, 300);
|
swiper.scrollTo(0, 300);
|
||||||
} else {
|
} else {
|
||||||
// 其他图片使用原有的slideTo方法,保持正常滚动
|
|
||||||
swiper.slideTo(index, 300);
|
swiper.slideTo(index, 300);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 静默处理错误
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 使用useCallback优化主图切换函数
|
|
||||||
const changeMainImage = useCallback((direction) => {
|
const changeMainImage = useCallback((direction) => {
|
||||||
if (data.attachments.length <= 1) return;
|
if (data.attachments.length <= 1) return;
|
||||||
|
|
||||||
@ -69,28 +60,23 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
|
|
||||||
setCurrentImageIndex(newIndex);
|
setCurrentImageIndex(newIndex);
|
||||||
|
|
||||||
// 自动滚动缩略图到对应位置
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
scrollThumbnailToIndex(newIndex);
|
scrollThumbnailToIndex(newIndex);
|
||||||
}, 100);
|
}, 100);
|
||||||
}, [currentImageIndex, data.attachments.length, scrollThumbnailToIndex]);
|
}, [currentImageIndex, data.attachments.length, scrollThumbnailToIndex]);
|
||||||
|
|
||||||
// 使用useCallback优化按索引切换主图函数
|
|
||||||
const changeMainImageByIndex = useCallback((index) => {
|
const changeMainImageByIndex = useCallback((index) => {
|
||||||
setCurrentImageIndex(index);
|
setCurrentImageIndex(index);
|
||||||
|
|
||||||
// 智能滚动缩略图到可见区域
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
scrollThumbnailToIndex(index);
|
scrollThumbnailToIndex(index);
|
||||||
}, 100);
|
}, 100);
|
||||||
}, [scrollThumbnailToIndex]);
|
}, [scrollThumbnailToIndex]);
|
||||||
|
|
||||||
// 初始化当前索引为主图索引
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentImageIndex(mainImageIndex);
|
setCurrentImageIndex(mainImageIndex);
|
||||||
}, [mainImageIndex]);
|
}, [mainImageIndex]);
|
||||||
|
|
||||||
// 键盘导航支持 - 使用useCallback优化
|
|
||||||
const handleKeyDown = useCallback((event) => {
|
const handleKeyDown = useCallback((event) => {
|
||||||
if (data.attachments.length <= 1) return;
|
if (data.attachments.length <= 1) return;
|
||||||
|
|
||||||
@ -126,7 +112,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
};
|
};
|
||||||
}, [handleKeyDown]);
|
}, [handleKeyDown]);
|
||||||
|
|
||||||
// 使用useMemo优化缩略图渲染
|
|
||||||
const thumbnailSlides = useMemo(() => {
|
const thumbnailSlides = useMemo(() => {
|
||||||
return data.attachments.map((attachment, index) => (
|
return data.attachments.map((attachment, index) => (
|
||||||
<SwiperSlide
|
<SwiperSlide
|
||||||
@ -143,7 +128,7 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
style={index === currentImageIndex ? { borderColor: '#1A1A1A', borderWidth: '2px' } : {}}
|
style={index === currentImageIndex ? { borderColor: '#1A1A1A', borderWidth: '2px' } : {}}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
role="button"
|
role="button"
|
||||||
aria-label={`查看图片 ${index + 1} / ${data.attachments.length}`}
|
aria-label={`View image ${index + 1} / ${data.attachments.length}`}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter' || e.key === ' ') {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -160,7 +145,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
e.target.style.display = 'none';
|
e.target.style.display = 'none';
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* 缩略图加载状态指示 */}
|
|
||||||
<div className="absolute inset-0 bg-gray-100 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
<div className="absolute inset-0 bg-gray-100 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
||||||
<div className="w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin"></div>
|
<div className="w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -172,7 +156,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="w-full md:w-120 flex justify-center md:justify-start mb-4 md:mb-0 max-w-full">
|
<div className="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 w-full max-w-[320px] md:max-w-full">
|
||||||
{/* 主图显示区域 */}
|
|
||||||
<div className="relative overflow-hidden rounded-xl shadow-lg mb-6 group/main-image">
|
<div className="relative overflow-hidden rounded-xl shadow-lg mb-6 group/main-image">
|
||||||
<img
|
<img
|
||||||
src={currentImage}
|
src={currentImage}
|
||||||
@ -181,14 +164,13 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 导航箭头 - 悬浮时显示 */}
|
|
||||||
{data.attachments.length > 1 && (
|
{data.attachments.length > 1 && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
className="absolute left-2 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-white/40 backdrop-blur-md rounded-full border-0 flex items-center justify-center shadow-[0_8px_32px_rgba(0,0,0,0.08)] hover:bg-white/60 hover:shadow-[0_12px_40px_rgba(0,0,0,0.12)] transition-all duration-500 ease-out z-10 focus:outline-none focus:ring-2 focus:ring-white/30 focus:ring-offset-2 focus:ring-offset-transparent opacity-0 group-hover/main-image:opacity-100 scale-90 group-hover/main-image:scale-100"
|
className="absolute left-2 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-white/40 backdrop-blur-md rounded-full border-0 flex items-center justify-center shadow-[0_8px_32px_rgba(0,0,0,0.08)] hover:bg-white/60 hover:shadow-[0_12px_40px_rgba(0,0,0,0.12)] transition-all duration-500 ease-out z-10 focus:outline-none focus:ring-2 focus:ring-white/30 focus:ring-offset-2 focus:ring-offset-transparent opacity-0 group-hover/main-image:opacity-100 scale-90 group-hover/main-image:scale-100"
|
||||||
onClick={() => changeMainImage('prev')}
|
onClick={() => changeMainImage('prev')}
|
||||||
aria-label={`上一张图片 (${currentImageIndex === 0 ? data.attachments.length : currentImageIndex} / ${data.attachments.length})`}
|
aria-label={`Previous image (${currentImageIndex === 0 ? data.attachments.length : currentImageIndex} / ${data.attachments.length})`}
|
||||||
title="上一张图片 (←)"
|
title="Previous image (←)"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
className="w-5 h-5 text-gray-700 hover:text-gray-900 transition-all duration-500 ease-out hover:scale-110"
|
className="w-5 h-5 text-gray-700 hover:text-gray-900 transition-all duration-500 ease-out hover:scale-110"
|
||||||
@ -205,8 +187,8 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
<button
|
<button
|
||||||
className="absolute right-2 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-white/40 backdrop-blur-md rounded-full border-0 flex items-center justify-center shadow-[0_8px_32px_rgba(0,0,0,0.08)] hover:bg-white/60 hover:shadow-[0_12px_40px_rgba(0,0,0,0.12)] transition-all duration-500 ease-out z-10 focus:outline-none focus:ring-2 focus:ring-white/30 focus:ring-offset-2 focus:ring-offset-transparent opacity-0 group-hover/main-image:opacity-100 scale-90 group-hover/main-image:scale-100"
|
className="absolute right-2 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-white/40 backdrop-blur-md rounded-full border-0 flex items-center justify-center shadow-[0_8px_32px_rgba(0,0,0,0.08)] hover:bg-white/60 hover:shadow-[0_12px_40px_rgba(0,0,0,0.12)] transition-all duration-500 ease-out z-10 focus:outline-none focus:ring-2 focus:ring-white/30 focus:ring-offset-2 focus:ring-offset-transparent opacity-0 group-hover/main-image:opacity-100 scale-90 group-hover/main-image:scale-100"
|
||||||
onClick={() => changeMainImage('next')}
|
onClick={() => changeMainImage('next')}
|
||||||
aria-label={`下一张图片 (${currentImageIndex === data.attachments.length - 1 ? 1 : currentImageIndex + 2} / ${data.attachments.length})`}
|
aria-label={`Next image (${currentImageIndex === data.attachments.length - 1 ? 1 : currentImageIndex + 2} / ${data.attachments.length})`}
|
||||||
title="下一张图片 (→)"
|
title="Next image (→)"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
className="w-5 h-5 text-gray-700 hover:text-gray-900 transition-all duration-500 ease-out hover:scale-110"
|
className="w-5 h-5 text-gray-700 hover:text-gray-900 transition-all duration-500 ease-out hover:scale-110"
|
||||||
@ -224,7 +206,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 缩略图列表 - 使用Swiper实现最佳滚动效果 */}
|
|
||||||
{data.attachments.length > 1 && (
|
{data.attachments.length > 1 && (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Swiper
|
<Swiper
|
||||||
@ -246,9 +227,7 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 内联样式 */}
|
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
/* 缩略图悬停效果 */
|
|
||||||
.thumbs-swiper .swiper-slide {
|
.thumbs-swiper .swiper-slide {
|
||||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
width: 64px !important;
|
width: 64px !important;
|
||||||
@ -266,7 +245,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
.thumbs-swiper .swiper-slide .border-2 {
|
.thumbs-swiper .swiper-slide .border-2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 导航按钮样式增强 */
|
|
||||||
.backdrop-blur-sm {
|
.backdrop-blur-sm {
|
||||||
backdrop-filter: blur(8px);
|
backdrop-filter: blur(8px);
|
||||||
-webkit-backdrop-filter: blur(8px);
|
-webkit-backdrop-filter: blur(8px);
|
||||||
@ -277,7 +255,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
-webkit-backdrop-filter: blur(12px);
|
-webkit-backdrop-filter: blur(12px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应式优化 */
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.thumbs-swiper .swiper-slide {
|
.thumbs-swiper .swiper-slide {
|
||||||
width: 4rem !important;
|
width: 4rem !important;
|
||||||
@ -285,12 +262,10 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 隐藏Swiper默认滚动条 */
|
|
||||||
.thumbs-swiper .swiper-scrollbar {
|
.thumbs-swiper .swiper-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 优化Swiper滑动体验 */
|
|
||||||
.thumbs-swiper {
|
.thumbs-swiper {
|
||||||
touch-action: pan-y pinch-zoom;
|
touch-action: pan-y pinch-zoom;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@ -303,7 +278,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
touch-action: manipulation;
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 加载状态动画 */
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
@ -314,7 +288,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
animation: spin 1s linear infinite;
|
animation: spin 1s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 焦点状态优化 */
|
|
||||||
.focus-within\\:ring-2:focus-within {
|
.focus-within\\:ring-2:focus-within {
|
||||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||||
@ -330,20 +303,17 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
--tw-ring-offset-width: 2px;
|
--tw-ring-offset-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 触摸设备优化 */
|
|
||||||
@media (hover: none) and (pointer: coarse) {
|
@media (hover: none) and (pointer: coarse) {
|
||||||
.thumbs-swiper .swiper-slide:hover {
|
.thumbs-swiper .swiper-slide:hover {
|
||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 强制导航箭头为圆形 */
|
|
||||||
.group\/main-image button {
|
.group\/main-image button {
|
||||||
border-radius: 50% !important;
|
border-radius: 50% !important;
|
||||||
-webkit-border-radius: 50% !important;
|
-webkit-border-radius: 50% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 高对比度模式支持 */
|
|
||||||
@media (prefers-contrast: high) {
|
@media (prefers-contrast: high) {
|
||||||
.border-gray-200 {
|
.border-gray-200 {
|
||||||
border-color: #000;
|
border-color: #000;
|
||||||
@ -358,7 +328,6 @@ const ProductImageGallery = ({ data }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 减少动画偏好 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.thumbs-swiper .swiper-slide,
|
.thumbs-swiper .swiper-slide,
|
||||||
.backdrop-blur-sm {
|
.backdrop-blur-sm {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user