微信公众号
扫描关注微信公众号
博客大厅

如何实现一个拖拽功能的 Hook?

原创 来源:博客站 阅读 0 03月23日 08:29 听全文

实现一个拖拽功能的 Hook 可以帮助你在多个组件中复用拖拽逻辑。这个 Hook 可以处理拖拽的开始、移动和结束事件,并管理拖拽状态。以下是如何实现一个拖拽功能的 Hook 的详细步骤和示例:

1. 创建拖拽功能的 Hook

首先,创建一个自定义 Hook useDrag,用于处理拖拽逻辑。

// useDrag.js
import { ref, onMounted, onUnmounted } from 'vue';

export function useDrag(elementRef) {
  const isDragging = ref(false);
  const startX = ref(0);
  const startY = ref(0);
  const offsetX = ref(0);
  const offsetY = ref(0);

  function onMouseDown(event) {
    isDragging.value = true;
    startX.value = event.clientX - offsetX.value;
    startY.value = event.clientY - offsetY.value;

    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
  }

  function onMouseMove(event) {
    if (isDragging.value) {
      offsetX.value = event.clientX - startX.value;
      offsetY.value = event.clientY - startY.value;
    }
  }

  function onMouseUp() {
    isDragging.value = false;
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
  }

  onMounted(() => {
    const element = elementRef.value;
    element.addEventListener('mousedown', onMouseDown);
  });

  onUnmounted(() => {
    const element = elementRef.value;
    element.removeEventListener('mousedown', onMouseDown);
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
  });

  return {
    isDragging,
    offsetX,
    offsetY
  };
}

2. 在组件中使用拖拽功能的 Hook

在组件中,你可以使用 useDrag Hook 来处理拖拽逻辑。

<template>
  <div ref="draggableElement" :style="{ transform: `translate(${offsetX}px, ${offsetY}px)` }">
    Drag me!
  </div>
</template>

<script>
import { ref } from 'vue';
import { useDrag } from './useDrag';

export default {
  setup() {
    const draggableElement = ref(null);
    const { isDragging, offsetX, offsetY } = useDrag(draggableElement);

    return {
      draggableElement,
      isDragging,
      offsetX,
      offsetY
    };
  }
};
</script>

3. <script setup> 语法中使用拖拽功能的 Hook

<script setup> 语法中,使用 useDrag Hook 更加简洁。

<template>
  <div ref="draggableElement" :style="{ transform: `translate(${offsetX}px, ${offsetY}px)` }">
    Drag me!
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useDrag } from './useDrag';

const draggableElement = ref(null);
const { isDragging, offsetX, offsetY } = useDrag(draggableElement);
</script>

4. 处理触摸事件

为了支持触摸设备,你可以在 useDrag Hook 中添加触摸事件的处理逻辑。

// useDrag.js
import { ref, onMounted, onUnmounted } from 'vue';

export function useDrag(elementRef) {
  const isDragging = ref(false);
  const startX = ref(0);
  const startY = ref(0);
  const offsetX = ref(0);
  const offsetY = ref(0);

  function onMouseDown(event) {
    startDrag(event.clientX, event.clientY);
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
  }

  function onTouchStart(event) {
    const touch = event.touches[0];
    startDrag(touch.clientX, touch.clientY);
    document.addEventListener('touchmove', onTouchMove);
    document.addEventListener('touchend', onTouchEnd);
  }

  function startDrag(clientX, clientY) {
    isDragging.value = true;
    startX.value = clientX - offsetX.value;
    startY.value = clientY - offsetY.value;
  }

  function onMouseMove(event) {
    moveDrag(event.clientX, event.clientY);
  }

  function onTouchMove(event) {
    const touch = event.touches[0];
    moveDrag(touch.clientX, touch.clientY);
  }

  function moveDrag(clientX, clientY) {
    if (isDragging.value) {
      offsetX.value = clientX - startX.value;
      offsetY.value = clientY - startY.value;
    }
  }

  function onMouseUp() {
    endDrag();
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
  }

  function onTouchEnd() {
    endDrag();
    document.removeEventListener('touchmove', onTouchMove);
    document.removeEventListener('touchend', onTouchEnd);
  }

  function endDrag() {
    isDragging.value = false;
  }

  onMounted(() => {
    const element = elementRef.value;
    element.addEventListener('mousedown', onMouseDown);
    element.addEventListener('touchstart', onTouchStart);
  });

  onUnmounted(() => {
    const element = elementRef.value;
    element.removeEventListener('mousedown', onMouseDown);
    element.removeEventListener('touchstart', onTouchStart);
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
    document.removeEventListener('touchmove', onTouchMove);
    document.removeEventListener('touchend', onTouchEnd);
  });

  return {
    isDragging,
    offsetX,
    offsetY
  };
}

5. 在组件中使用支持触摸的拖拽功能 Hook

在组件中,你可以使用支持触摸的 useDrag Hook。

<template>
  <div ref="draggableElement" :style="{ transform: `translate(${offsetX}px, ${offsetY}px)` }">
    Drag me!
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useDrag } from './useDrag';

const draggableElement = ref(null);
const { isDragging, offsetX, offsetY } = useDrag(draggableElement);
</script>

6. 处理边界限制

你可以添加边界限制逻辑,确保拖拽元素不会超出指定的边界。

// useDrag.js
import { ref, onMounted, onUnmounted } from 'vue';

export function useDrag(elementRef, bounds = { top: 0, right: 0, bottom: 0, left: 0 }) {
  const isDragging = ref(false);
  const startX = ref(0);
  const startY = ref(0);
  const offsetX = ref(0);
  const offsetY = ref(0);

  function onMouseDown(event) {
    startDrag(event.clientX, event.clientY);
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
  }

  function onTouchStart(event) {
    const touch = event.touches[0];
    startDrag(touch.clientX, touch.clientY);
    document.addEventListener('touchmove', onTouchMove);
    document.addEventListener('touchend', onTouchEnd);
  }

  function startDrag(clientX, clientY) {
    isDragging.value = true;
    startX.value = clientX - offsetX.value;
    startY.value = clientY - offsetY.value;
  }

  function onMouseMove(event) {
    moveDrag(event.clientX, event.clientY);
  }

  function onTouchMove(event) {
    const touch = event.touches[0];
    moveDrag(touch.clientX, touch.clientY);
  }

  function moveDrag(clientX, clientY) {
    if (isDragging.value) {
      let newOffsetX = clientX - startX.value;
      let newOffsetY = clientY - startY.value;

      // Apply boundary constraints
      newOffsetX = Math.max(bounds.left, Math.min(bounds.right, newOffsetX));
      newOffsetY = Math.max(bounds.top, Math.min(bounds.bottom, newOffsetY));

      offsetX.value = newOffsetX;
      offsetY.value = newOffsetY;
    }
  }

  function onMouseUp() {
    endDrag();
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
  }

  function onTouchEnd() {
    endDrag();
    document.removeEventListener('touchmove', onTouchMove);
    document.removeEventListener('touchend', onTouchEnd);
  }

  function endDrag() {
    isDragging.value = false;
  }

  onMounted(() => {
    const element = elementRef.value;
    element.addEventListener('mousedown', onMouseDown);
    element.addEventListener('touchstart', onTouchStart);
  });

  onUnmounted(() => {
    const element = elementRef.value;
    element.removeEventListener('mousedown', onMouseDown);
    element.removeEventListener('touchstart', onTouchStart);
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
    document.removeEventListener('touchmove', onTouchMove);
    document.removeEventListener('touchend', onTouchEnd);
  });

  return {
    isDragging,
    offsetX,
    offsetY
  };
}

7. 在组件中使用带边界限制的拖拽功能 Hook

在组件中,你可以使用带边界限制的 useDrag Hook。

<template>
  <div ref="draggableElement" :style="{ transform: `translate(${offsetX}px, ${offsetY}px)` }">
    Drag me!
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useDrag } from './useDrag';

const draggableElement = ref(null);
const bounds = { top: 0, right: window.innerWidth - 100, bottom: window.innerHeight - 100, left: 0 };
const { isDragging, offsetX, offsetY } = useDrag(draggableElement, bounds);
</script>

总结

  • 通过自定义 Hook useDrag,你可以封装拖拽逻辑,使其在多个组件中复用。
  • useDrag Hook 可以处理鼠标和触摸事件,并管理拖拽状态。
  • 在组件中,你可以像使用普通函数一样使用 useDrag Hook,返回的响应式数据和方法可以直接在模板中使用。
  • <script setup> 语法中,使用 useDrag Hook 更加简洁。
  • 可以通过添加边界限制逻辑来确保拖拽元素不会超出指定的边界。
学在每日,进无止境!更多精彩内容请关注微信公众号。
原文出处: 内容由AI生成仅供参考,请勿使用于商业用途。如若转载请注明原文及出处。
出处地址:http://www.07sucai.com/tech/877.html
版权声明:本文来源地址若非本站均为转载,若侵害到您的权利,请及时联系我们,我们会在第一时间进行处理。
>