- 移除手算高度逻辑,自适应模式启用 swiper 原生 autoHeight - image 保持 mode=widthFix,完整展示不裁切 - 删除 .detail-carousel-wrap 固定比例/高度的覆盖依赖 Co-Authored-By: WorkBuddy <workbuddy@tencent.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { View, Image, Swiper, SwiperItem } from '@tarojs/components';
|
import { View, Image, Swiper, SwiperItem } from '@tarojs/components';
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ type ProductCarouselProps = {
|
|||||||
* cover=aspectFill 裁剪铺满(固定高度,可能裁切)
|
* cover=aspectFill 裁剪铺满(固定高度,可能裁切)
|
||||||
* contain=aspectFit 完整显示(固定高度,可能留白)
|
* contain=aspectFit 完整显示(固定高度,可能留白)
|
||||||
* adaptive=widthFix 按图片真实比例自适应高度,完整显示不裁剪(门店套餐详情用)
|
* adaptive=widthFix 按图片真实比例自适应高度,完整显示不裁剪(门店套餐详情用)
|
||||||
|
* 依赖 swiper 原生 auto-height:海报有多高,轮播就有多高,无裁切。
|
||||||
*/
|
*/
|
||||||
imageFit?: 'cover' | 'contain' | 'adaptive';
|
imageFit?: 'cover' | 'contain' | 'adaptive';
|
||||||
};
|
};
|
||||||
@@ -25,56 +26,12 @@ export default function ProductCarousel({
|
|||||||
}: ProductCarouselProps) {
|
}: ProductCarouselProps) {
|
||||||
const slides = images.length > 0 ? images : [''];
|
const slides = images.length > 0 ? images : [''];
|
||||||
const [activeIndex, setActiveIndex] = useState(0);
|
const [activeIndex, setActiveIndex] = useState(0);
|
||||||
// adaptive 模式:实测容器宽度与各图渲染高度
|
|
||||||
const [wrapWidth, setWrapWidth] = useState(0);
|
|
||||||
const [imgHeights, setImgHeights] = useState<number[]>([]);
|
|
||||||
const prefix =
|
const prefix =
|
||||||
variant === 'store' ? 'store-detail-carousel' : variant === 'home' ? 'home-carousel' : 'detail-carousel';
|
variant === 'store' ? 'store-detail-carousel' : variant === 'home' ? 'home-carousel' : 'detail-carousel';
|
||||||
const isContain = imageFit === 'contain';
|
const isContain = imageFit === 'contain';
|
||||||
const isAdaptive = imageFit === 'adaptive';
|
const isAdaptive = imageFit === 'adaptive';
|
||||||
const wrapClass = `${prefix}-wrap${isContain ? ` ${prefix}-wrap--contain` : ''}${isAdaptive ? ` ${prefix}-wrap--adaptive` : ''}`;
|
const wrapClass = `${prefix}-wrap${isContain ? ` ${prefix}-wrap--contain` : ''}${isAdaptive ? ` ${prefix}-wrap--adaptive` : ''}`;
|
||||||
|
|
||||||
function getWindowWidth(): number {
|
|
||||||
try {
|
|
||||||
const info = (Taro as any).getWindowInfo?.() ?? Taro.getSystemInfoSync();
|
|
||||||
return info?.windowWidth || 375;
|
|
||||||
} catch {
|
|
||||||
return 375;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isAdaptive) return;
|
|
||||||
const query = Taro.createSelectorQuery();
|
|
||||||
query
|
|
||||||
.select(`.${prefix}-wrap--adaptive`)
|
|
||||||
.boundingClientRect((rect: { width?: number }) => {
|
|
||||||
if (rect && rect.width) setWrapWidth(rect.width);
|
|
||||||
else setWrapWidth(getWindowWidth());
|
|
||||||
})
|
|
||||||
.exec();
|
|
||||||
// 仅挂载时测量一次容器宽度(页面宽度稳定)
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [isAdaptive, prefix]);
|
|
||||||
|
|
||||||
function handleImageLoad(index: number, e: any) {
|
|
||||||
const detail = e?.detail;
|
|
||||||
const naturalW = detail?.width;
|
|
||||||
const naturalH = detail?.height;
|
|
||||||
if (!naturalW || !naturalH) return;
|
|
||||||
const w = wrapWidth || getWindowWidth();
|
|
||||||
const h = Math.round((naturalH / naturalW) * w);
|
|
||||||
setImgHeights((prev) => {
|
|
||||||
const next = [...prev];
|
|
||||||
next[index] = h;
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// adaptive:随当前幻灯片高度变化;未加载时给一个 3:4 兜底高度
|
|
||||||
const adaptiveHeight = imgHeights[activeIndex] || Math.round((wrapWidth || getWindowWidth()) * 0.75);
|
|
||||||
const swiperStyle = isAdaptive ? { height: `${adaptiveHeight}px` } : undefined;
|
|
||||||
|
|
||||||
function previewAt(index: number) {
|
function previewAt(index: number) {
|
||||||
const urls = slides.filter(Boolean);
|
const urls = slides.filter(Boolean);
|
||||||
if (!urls.length) return;
|
if (!urls.length) return;
|
||||||
@@ -86,8 +43,8 @@ export default function ProductCarousel({
|
|||||||
<View className={wrapClass}>
|
<View className={wrapClass}>
|
||||||
<Swiper
|
<Swiper
|
||||||
className={prefix}
|
className={prefix}
|
||||||
style={swiperStyle}
|
|
||||||
circular={slides.length > 1}
|
circular={slides.length > 1}
|
||||||
|
autoHeight={isAdaptive}
|
||||||
{...(variant === 'detail' && slides.length > 1 ? { autoplay: true, interval: 3500 } : {})}
|
{...(variant === 'detail' && slides.length > 1 ? { autoplay: true, interval: 3500 } : {})}
|
||||||
onChange={(e) => setActiveIndex(e.detail.current)}
|
onChange={(e) => setActiveIndex(e.detail.current)}
|
||||||
>
|
>
|
||||||
@@ -99,7 +56,6 @@ export default function ProductCarousel({
|
|||||||
src={src}
|
src={src}
|
||||||
mode={isAdaptive ? 'widthFix' : isContain ? 'aspectFit' : 'aspectFill'}
|
mode={isAdaptive ? 'widthFix' : isContain ? 'aspectFit' : 'aspectFill'}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
onLoad={isAdaptive ? (e) => handleImageLoad(index, e) : undefined}
|
|
||||||
onClick={previewable ? () => previewAt(index) : undefined}
|
onClick={previewable ? () => previewAt(index) : undefined}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -18,17 +18,15 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adaptive 模式:去掉固定 1:1 比例,按图片真实比例自适应高度,完整显示不裁剪 */
|
/* adaptive 模式(方案 A):删除固定 1:1 比例与固定高度,
|
||||||
|
改用 swiper 原生 auto-height + image widthFix,海报有多高轮播就有多高,无裁切 */
|
||||||
.detail-carousel-wrap--adaptive {
|
.detail-carousel-wrap--adaptive {
|
||||||
aspect-ratio: auto;
|
aspect-ratio: auto;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-carousel-wrap--adaptive .detail-carousel {
|
.detail-carousel-wrap--adaptive .detail-carousel,
|
||||||
height: auto;
|
.detail-carousel-wrap--adaptive .detail-carousel-item,
|
||||||
transition: height 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-carousel-wrap--adaptive .detail-carousel-image {
|
.detail-carousel-wrap--adaptive .detail-carousel-image {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user