【问题标题】:React horizontal swiper scrolls but doesn't drag反应水平滑动器滚动但不拖动
【发布时间】:2021-05-28 22:07:33
【问题描述】:

我已经制作了这个水平滑动器,它可以左右滚动,但是当我尝试左右拖动时,它什么也没做。我希望能够左右滚动和左右拖动。

如果我向左或向右滚动,然后移动光标,它会一直向左滚动。

import React, { useRef, useState, useEffect } from "react";

export default function Swiper() {
  const ref = useRef(null);
  const [startX, setStartX] = useState<number>(0);
  const [startScrollLeft, setStartScrollLeft] = useState<number>(0);
  const [myMouseDown, setMyMouseDown] = useState<boolean>(false);

  const handleDown = (e: any) => {
    console.log("down");
    if (!ref.current.contains(e.target)) return;
    setMyMouseDown(true);// <=============================== This makes it true
    setStartX(e.pageX - ref.current.offsetLeft);
    setStartScrollLeft(ref.current.scrollLeft);
  };

  const handleMove = (e: any) => {
    console.log(myMouseDown);// Why this always false when I mouse down and move?
    e.preventDefault();
    if (!ref.current.contains(e.target)) return;
    const mouseX = e.pageX - ref.current.offsetLeft;
    const moveX = mouseX - startX;
    if (myMouseDown) {
      console.log("move"); // <==================================== never fires!
      ref.current.scrollLeft = startScrollLeft - moveX;
    }
  };

  const handleUp = () => {
    console.log("up");
    setMyMouseDown(false); // <=========================== This makes it false
  };

  useEffect(() => {
    document.addEventListener("mouseup", handleUp);
    document.addEventListener("mousedown", handleDown);
    document.addEventListener("mousemove", handleMove);
    return () => {
      document.removeEventListener("mouseup", handleUp);
      document.removeEventListener("mousedown", handleDown);
      document.removeEventListener("mousemove", handleMove);
    };
  }, []);

  const handleScroll = (e: any) => {
    const { scrollWidth, scrollLeft, clientWidth } = e.target;
    if (scrollLeft + clientWidth === scrollWidth) console.log("end");
    if (scrollLeft === 0) console.log("start");
  };

  return (
    <header className="container">
      {startX} - {startScrollLeft} - {JSON.stringify(myMouseDown)}
      <ul onScroll={handleScroll} ref={ref}>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li>Item 5</li>
        <li>Item 6</li>
        <li>Item 7</li>
        <li>Item 8</li>
      </ul>
      <style jsx>{`
        ul {
          overflow-x: auto;
          overflow-y: hidden;
          white-space: nowrap;
          height: 260px;
          cursor: grab;
          padding: 0;
          display: grid;
          grid-gap: 20px;
          grid-template-columns: repeat(8, 260px);
        }
        ul::-webkit-scrollbar {
          background: #ebeced;
          height: 6px;
          margin: 0 20px;
        }
        ul::-webkit-scrollbar-thumb {
          background: #c8cad0;
        }
        li {
          display: inline-block;
          vertical-align: top;
          width: 230px;
          height: 230px;
          white-space: normal;
          background: grey;
        }
      `}</style>
    </header>
  );
}

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

    你需要在useEffect钩子中更新你的依赖:

    useEffect(() => {
      document.addEventListener("mouseup", handleUp);
      document.addEventListener("mousedown", handleDown);
      document.addEventListener("mousemove", handleMove);
      return () => {
        document.removeEventListener("mouseup", handleUp);
        document.removeEventListener("mousedown", handleDown);
        document.removeEventListener("mousemove", handleMove);
      };
    }, [handleDown, handleMove]);
    

    那么你需要在你的处理程序中使用 useCallback 钩子:

    const handleDown = useCallback((e: any) => {
      console.log("down");
      setMyMouseDown(true); // <=============================== This makes it true
      if (!ref.current.contains(e.target)) return;
      setStartX(e.pageX - ref.current.offsetLeft);
      setStartScrollLeft(ref.current.scrollLeft);
    }, []);
    
    const handleMove = useCallback(
      (e: any) => {
        e.preventDefault();
        console.log("myMouseDown", myMouseDown); // Why this always false when I mouse down and move?
        if (!ref.current.contains(e.target)) return;
        const mouseX = e.pageX - ref.current.offsetLeft;
        const moveX = mouseX - startX;
        if (myMouseDown) {
          console.log("move"); // <==================================== never fires!
          ref.current.scrollLeft = startScrollLeft - moveX;
        }
      },
      [myMouseDown, startScrollLeft, startX]
    );
    

    工作代码:https://codesandbox.io/s/pedantic-sanne-mfp9i?file=/src/App.tsx

    顺便说一句。 为每个事件设置状态不是最佳的。您应该在这里使用 useRef 而不是 useState:

    const startX = useRef<number>(0);
    
    startX.current = e.pageX - ref.current.offsetLeft;
    
    const moveX = mouseX - startX.current;
    

    【讨论】:

    • Bart,看起来不错,这个周末我去测试一下,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2021-03-23
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 2016-08-05
    相关资源
    最近更新 更多