反应水平滑动条滚动但不拖动

时间:2021-05-23 17:39:45

标签: reactjs typescript

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

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

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>
  );
}

1 个答案:

答案 0 :(得分: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;