Recommended way of making React component/div draggable

后端 未结 9 705
耶瑟儿~
耶瑟儿~ 2020-11-28 18:13

I want to make a draggable (that is, repositionable by mouse) React component, which seems to necessarily involve global state and scattered event handlers. I can do it the

9条回答
  •  我在风中等你
    2020-11-28 18:51

    Here's a 2020 answer with a Hook:

    function useDragging() {
      const [isDragging, setIsDragging] = useState(false);
      const [pos, setPos] = useState({ x: 0, y: 0 });
      const ref = useRef(null);
    
      function onMouseMove(e) {
        if (!isDragging) return;
        setPos({
          x: e.x - ref.current.offsetWidth / 2,
          y: e.y - ref.current.offsetHeight / 2,
        });
        e.stopPropagation();
        e.preventDefault();
      }
    
      function onMouseUp(e) {
        setIsDragging(false);
        e.stopPropagation();
        e.preventDefault();
      }
    
      function onMouseDown(e) {
        if (e.button !== 0) return;
        setIsDragging(true);
    
        setPos({
          x: e.x - ref.current.offsetWidth / 2,
          y: e.y - ref.current.offsetHeight / 2,
        });
    
        e.stopPropagation();
        e.preventDefault();
      }
    
      // When the element mounts, attach an mousedown listener
      useEffect(() => {
        ref.current.addEventListener("mousedown", onMouseDown);
    
        return () => {
          ref.current.removeEventListener("mousedown", onMouseDown);
        };
      }, [ref.current]);
    
      // Everytime the isDragging state changes, assign or remove
      // the corresponding mousemove and mouseup handlers
      useEffect(() => {
        if (isDragging) {
          document.addEventListener("mouseup", onMouseUp);
          document.addEventListener("mousemove", onMouseMove);
        } else {
          document.removeEventListener("mouseup", onMouseUp);
          document.removeEventListener("mousemove", onMouseMove);
        }
        return () => {
          document.removeEventListener("mouseup", onMouseUp);
          document.removeEventListener("mousemove", onMouseMove);
        };
      }, [isDragging]);
    
      return [ref, pos.x, pos.y, isDragging];
    }
    

    Then a component that uses the hook:

    
    function Draggable() {
      const [ref, x, y, isDragging] = useDragging();
    
      return (
        
    ); }

提交回复
热议问题