【发布时间】:2021-11-30 19:16:08
【问题描述】:
我有 Carousel 组件,它呈现它的孩子并一次显示一个孩子(每个孩子都是一个图像)。该组件由“viewport-div”和“wrapper-div”组成。 Wrapper-div 包含所有图像。为了更改活动图像,我更改了 wrapper-div 的 css-transform。 Carousel 组件采用 'ActiveImage' 属性来定义正在显示的孩子。例如,如果我将 ActiveImage 属性从 x 更改为 y,wrapper-div 会滑动到图像 y,并且我应该能够在此动画期间看到每个图像。但是,当 new 和 previous ActiveImage 值之间的差异大于 6 时,比如说从 0 到 10,我只能看到 6 个图像,图像 7,8 和 9是不可见的,并且当动画结束时,正在显示图像 10,但仅当屏幕上没有发生任何事情时才会出现此问题,即如果我单击屏幕上的任意位置,按随机键或滚动一切正常。 所有图像都被缩小(~100kb),这就是我导入它们的方式:
export const images = new Array(30).fill(null)
.map((image, number)=>{
const name = number > 8 ? `${number+1}-min` : `0${number+1}-min`
return {
src: process.env.PUBLIC_URL + `/images/min/${name}.jpg`,
alt:name
}
})
我认为这与组件逻辑无关,但以防万一这里是代码:
import React, {FC, useEffect, useRef, useState} from 'react';
import styles from './Carousel.module.scss';
type CarouselProps = {
activeSlideNumber?: number
}
const Carousel: FC<CarouselProps> = ({children, activeSlideNumber}) => {
const [width, setWidth] = useState(0);
const [allowStartDrag, setAllowStartDrag] = useState(true);
const [isDragging, setIsDragging] = useState(false); // enables carousel move
const [xCoord, setXCoord] = useState(0);
const [currentShift, setCurrentShift] = useState(0);
const [savedShift, setSavedShift] = useState(0);
const [activeSlide, setActiveSlide] = useState(0);
const itemsCount = React.Children.toArray(children).length;
const wrapperRef = useRef<null | HTMLDivElement>(null); // carousel viewport
const lineRef = useRef<null | HTMLDivElement>(null); // carousel draggable line
let timeout = null as null | NodeJS.Timeout;
useEffect(()=>{
if (activeSlideNumber!==undefined) setActiveSlide(activeSlideNumber)
},[activeSlideNumber])
useEffect(() => {
if (lineRef.current) {
setAllowStartDrag(false);
if (timeout) {
clearTimeout(timeout)
}
const slidesPerSweep = Math.abs((currentShift - activeSlide * width) / width);
const slowDownCoeff = 0.25 * slidesPerSweep;
setCurrentShift(activeSlide * width);
setSavedShift(activeSlide*width);
lineRef.current.style.transition = `transform ${slowDownCoeff}s ease 0s`;
lineRef.current.style.transform = `translateX(${-activeSlide * width}px)`;
timeout = setTimeout(() => {
if (lineRef.current) {
lineRef.current.style.transition = ``;
}
setAllowStartDrag(true);
}, slowDownCoeff * 1000)
}
}, [activeSlide])
useEffect(() => {
if (wrapperRef.current) setWidth(wrapperRef.current.clientWidth)
}, [width])
const onDrag = (e: React.PointerEvent<HTMLDivElement>) => {
if (!isDragging) return
const shift = xCoord - e.pageX;
setCurrentShift(() => {
if (shift + savedShift < 0) return 0
if (shift + savedShift > (itemsCount - 1) * width) return (itemsCount - 1) * width
return shift + savedShift
});
e.currentTarget.style.transform = `translate(${-currentShift}px)`;
}
const onSwipeStart = (e: React.PointerEvent) => {
if (!allowStartDrag) return
setXCoord(e.pageX);
setIsDragging(true);
}
const completeSwipe = () => {
if (currentShift > savedShift ) {
setActiveSlide(p => p + 1);
} else if (currentShift < savedShift) {
setActiveSlide(p => p - 1);
}
}
const onSwipeEnd = (e: React.PointerEvent) => {
completeSwipe();
setIsDragging(false);
}
const onMouseLeave = (e: React.PointerEvent) => {
completeSwipe();
setIsDragging(false)
}
return (
<div className={styles.wrapper} style={{
width: `${width}px`
}}>
<div className={styles.item_line}
ref={lineRef}
onPointerDown={onSwipeStart}
onPointerUp={onSwipeEnd}
onPointerMove={onDrag}
onPointerLeave={onMouseLeave}
>
{React.Children.toArray(children).map((child, i) => {
return (
<div key={i} ref={i === 0 ? wrapperRef : undefined} className={styles.item}>
{child}
</div>
)
})}
</div>
<div className={styles.arrow_left}>
<button onClick={()=>setActiveSlide(p=> p === 0 ? p : p - 1)}>previous</button>
</div>
<div className={styles.arrow_right}>
<button onClick={()=>setActiveSlide(p=> p === itemsCount - 1 ? p : p + 1)}>next</button>
</div>
</div>
);
};
export default Carousel;
我能找到的唯一一些相关的东西是 React Native 渲染错误,但我对 ReactNative 不熟悉,所以希望你能帮助我。
编辑
在动画期间调度事件或更改图像样式不会改变任何内容。只有当我在浏览器中手动单击/滚动/鼠标移动/键入时,错误才会消失(Chrome v.96.0.4664.45)。
在 Firefox v.94.0.1 中一切正常。 在 Opera v.81.0.4196.60 中,很少有图像会在一段时间内消失,几乎看不到。看起来像 Crome 的行为,但是一旦图像消失,它就会再次渲染。 在 Edge v.96.0.1054.34 中,几乎与 Opera 中一样,但“闪烁”的时间要长一些。
对于所有列出的浏览器(Firefox 除外,因为一切正常),在动画期间手动单击/滚动等可以解决问题。
【问题讨论】: