react实现自定义hooks(移动端拖拽)

实现思路

通过touchstart、touchmove、touchend组合,实现过程中需要注意以下几个问题

  1. touchmove、touchend事件需要绑定在window上,并且这两个事件需要包在touchstart中
  2. touchstart事件需要阻止冒泡和禁止默认事件,开始监听touchmove和touchmove。组件销毁前要记得移除事件监听
  3. touchend事件里要移除事件监听
  4. touchmove计算位置值,弄清楚event.clientX和element.offsetTop等关系
  5. 定位不要使用position,应该使用transform的translate

在线预览

react移动端拖拽hooks

核心代码

import { useEffect, useState, useRef } from "react";
import "./styles.css";
/***
 * 请在移动端查看
 */
const docWidth = document.documentElement.clientWidth;
const docHeight = document.documentElement.clientHeight;

export default function useMobileDrag(props) {
  const touchStartX = useRef(0);
  const touchStartY = useRef(0);
  const [x, setX] = useState(0);
  const [y, setY] = useState(0);

  const { targetDomRef } = props;

  useEffect(() => {
    if (!targetDomRef?.current) {
      return;
    }

    const target = targetDomRef.current;
    const { width, height } = target.getBoundingClientRect();
    const touchmove = (e) => {
      const { clientX, clientY } = e.targetTouches[0];
      if (clientX - touchStartX.current >= docWidth - width) {
        setX(docWidth - width);
      } else if (clientX - touchStartX.current <= 0) {
        setX(0);
      } else {
        setX(clientX - touchStartX.current);
      }
      if (clientY - touchStartY.current >= docHeight - height) {
        setY(docHeight - height);
      } else if (clientY - touchStartY.current <= 0) {
        setY(0);
      } else {
        setY(clientY - touchStartY.current);
      }
    };
    const touchend = () => {
      window.removeEventListener("touchmove", touchmove);
      window.removeEventListener("touchend", touchend);
    };
    const touchstart = (e) => {
      e.stopPropagation();
      e.preventDefault();
      const { top, left } = target?.getBoundingClientRect();
      const { clientX, clientY } = e.targetTouches[0];
      touchStartX.current = clientX - left;
      touchStartY.current = clientY - top;

      window.addEventListener("touchmove", touchmove);
      window.addEventListener("touchend", touchend);
    };
    target.addEventListener("touchstart", touchstart);
    return () => {
      target.removeEventListener("touchstart", touchstart);
    };
  }, [targetDomRef]);
  return { x, y };
}

原文地址:https://www.cnblogs.com/xingguozhiming/p/15777906.html