Динамически менять ширину центрального слайда
Пишу карусель используя swiper и next.js 13, но столкнулся с проблемой что при изменение ширины активного слайда (который по середине), то данный слайд не по середине а чуть в сторону.
Использовал ResizeObserver для отслеживания изменения ширины выбранного слайда, но в данном случае слайд не перемещается плавно к центру и телепотируется. Как сделать плавную анимацию изменения ширину выбраного блока (без использования scale)?
const Carousel: React.FC = () => {
const [swiperRef, setSwiperRef] = useState<SwiperClass>(null);
const [clickedSlide, setClickedSlide] = useState<number>();
const handleClickSlide = (swiper: SwiperClass) => {
setClickedSlide(swiper.clickedIndex);
};
return (
<ClickAwayListener onClickAway={() => setClickedSlide(undefined)} mouseEvent="onMouseDown">
<div className={classNames(style['swiper-container'])}>
<div className={style['swiper-prev']}>←</div>
<Swiper
onSwiper={setSwiperRef}
onClick={handleClickSlide}
direction="horizontal"
slidesPerView="auto"
speed={600}
slideToClickedSlide
centeredSlides
resizeObserver
freeMode
navigation={{
nextEl: '.' + style['swiper-next'],
prevEl: '.' + style['swiper-prev'],
}}
mousewheel={{
sensitivity: 0.5,
}}
modules={[Navigation, Mousewheel, Manipulation]}
>
{
slides.map((slide) => {
const active = clickedSlide == index;
return (
<SwiperSlide className={classNames(style['swiper-slide'], active && style['swiper-slide-active'])}>
<SlideComponent slide={slide} active={active} swiper={swiperRef} />
</SwiperSlide>
);
})
}
</Swiper>
<div className={style['swiper-next']}> →</div>
</div>
</ClickAwayListener>
);
};
SlideComponent.tsx
const SlideComponent = React.forwardRef<HTMLDivElement, MapCarouselSlideProps>(({
job,
className,
active,
swiper,
...props
}, ref) => {
const slide = useRef<HTMLDivElement>(null);
useImperativeHandle(ref, () => slide.current!, []);
useEffect(() => {
if (!slide.current) {
return;
}
const observer = new ResizeObserver(() => swiper.update());
observer.observe(slide.current);
return () => observer.disconnect();
}, [active]);
return (
<div ref={slide} className={classNames(style['slide-component'], className)} {...props} >
text
</div>
);
});
CSS
.swiper-slide {
flex-basis: 280px;
width: 280px;
overflow: hidden;
padding: 16px;
transition: flex-basis 500ms ease-in-out !important;
}
.swiper-slide-active {
flex-basis: 520px;
width: 520px;
}
В поисках решение наткнулся на вопросы в git проекта swiper:
add width to swiper-slide-active makes centeredSlides to fail
Ответы (1 шт):
Исправил используя костыль
Добавил стиль для map-carousel-wrapper
.map-carousel-wrapper {
align-items: flex-end;
transition: all 300ms linear !important;
}
и ResizeObserver
для каждого слайда
useEffect(() => {
if (!slide.current) {
return;
}
const observer = new ResizeObserver(() => swiper.update());
observer.observe(slide.current);
return () => observer.disconnect();
}, [active]);