Javascript React中的简单旋转木马-如何注册滚动到下一张幻灯片?

Javascript React中的简单旋转木马-如何注册滚动到下一张幻灯片?,javascript,css,reactjs,carousel,react-hooks,Javascript,Css,Reactjs,Carousel,React Hooks,这是一个相对简单的问题,但我一直未能解决它。我构建了以下转盘/滑块: const BlogPostCardSlider = ({ children }) => { const [activeSlide, setActiveSlide] = useState(0); const activeSlideRef = useRef(null); const wrapperRef = useRef(null); const firstRenderRef = useRef(true);

这是一个相对简单的问题,但我一直未能解决它。我构建了以下转盘/滑块:

const BlogPostCardSlider = ({ children }) => {
  const [activeSlide, setActiveSlide] = useState(0);
  const activeSlideRef = useRef(null);
  const wrapperRef = useRef(null);
  const firstRenderRef = useRef(true);

  useEffect(() => {
    if (firstRenderRef.current) {
      //this is checking whether its the first render of the component. If it is, we dont want useEffect to run.
      firstRenderRef.current = false;
    } else if (activeSlideRef.current) {
      activeSlideRef.current.scrollIntoView({
        behavior: 'smooth',
        block: 'nearest',
        inline: 'nearest'
      });
    }
  }, [activeSlide]);

  const moveRight = () => {
    if (activeSlide + 1 >= children.length) {
      return children.length - 1;
    }
    return activeSlide + 1;
  };

  const moveLeft = () => {
    if (activeSlide - 1 <= 0) {
      return 0;
    }
    return activeSlide - 1;
  };

  return (
    <div id="trap" tabIndex="0">
      <button onClick={() => setActiveSlide(moveLeft)}>PREV</button>

      {children.map((child, i) => {
        return (
          <SlideLink
            key={`slideLink-${i}`}
            isActive={activeSlide === i}
            onClick={e => {
              setActiveSlide(i);
            }}
          >
            {i + 1}
          </SlideLink>
        );
      })}

      <Wrapper
        onScroll={e => {
          let { width } = wrapperRef.current.getBoundingClientRect();
          let { scrollLeft } = wrapperRef.current;

          if ((scrollLeft / width) % 1 === 0) {
            setActiveSlide(scrollLeft / width);
          }
        }}
        ref={wrapperRef}
      >
        {children.map((child, i) => {
          return (
            <Slide
              key={`slide-${i}`}
              ref={i === activeSlide ? activeSlideRef : null}
            >
              {child}
            </Slide>
          );
        })}
      </Wrapper>

      <button onClick={() => setActiveSlide(moveRight)}>NEXT</button>
    </div>
  );
};

export default BlogPostCardSlider;
…这样做的结果是,
setActiveSlide
仅在幻灯片完全显示在视图中时调用。这会产生一种滞后的体验:用户已滚动到下一张幻灯片,下一张幻灯片显示在视图中,但计算尚未完成(因为只有在幻灯片100%显示在视图中时才完成),因此,在这个过程中,活动的SlideLink会在很晚的时候更新


我该如何解决这个问题?有什么方法可以乐观地更新这个吗?

乍一看,我认为这应该是一个快速解决方案。结果证明需要更多一点。我在这里创建了一个工作示例:


要点是,在
onScroll
事件期间不应调用
setActiveSide
,而应在用户完成滚动时调用。这是在示例中使用onIdlereact钩子实现的。

您可以稍微修改计算,以便当幻灯片在视图中超过50%时,将active属性设置为该属性

onScroll={e => {
    let { width } = wrapperRef.current.getBoundingClientRect();
    let { scrollLeft } = wrapperRef.current;
    setActiveSlide(Math.round(scrollLeft / width) + 1);
}}
示例:宽度为800px的旋转木马,总幻灯片数为3张。所以,scrollLeft将从0到1600变化

  • 从0到400:活动幻灯片=数学圆(滚动左/宽)=第0个索引 (或第一张幻灯片)
  • 从400-1200:活动幻灯片=第一个索引(或第二个索引 幻灯片)因为它更多地出现在视图中
  • 从1200-1600:活动幻灯片= 第二个索引(或第三张幻灯片),因为它更在视图中

希望能有帮助。如果有任何疑问,请回复。

如果您在此处提供演示,我认为这将非常有用。
onScroll={e => {
    let { width } = wrapperRef.current.getBoundingClientRect();
    let { scrollLeft } = wrapperRef.current;
    setActiveSlide(Math.round(scrollLeft / width) + 1);
}}