盒子拖拽位置、更改

<template>
  <div class="container" ref="container">
    <!-- 可拖动的盒子 -->
    <div
      class="box"
      ref="box"
      :style="{
        width: `${width}px`,
        height: `${height}px`,
        left: `${left}px`,
        top: `${top}px`,
      }"
      @mousedown="startDrag"
    >
      <!-- 四个调整大小的控制点 -->
      <div
        class="resize-handle top-left"
        @mousedown="startResize('top-left', $event)"
      ></div>
      <div
        class="resize-handle top-right"
        @mousedown="startResize('top-right', $event)"
      ></div>
      <div
        class="resize-handle bottom-left"
        @mousedown="startResize('bottom-left', $event)"
      ></div>
      <div
        class="resize-handle bottom-right"
        @mousedown="startResize('bottom-right', $event)"
      ></div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { onMounted, reactive, ref, computed, onUnmounted } from 'vue';
// 控制盒子是否正在拖动的状态
const isDragging = ref(false);
// 控制盒子是否调整大小的状态
const isResizing = ref(false);
// 初始化拖动和调整大小相关的状态
// 记录拖拽或调整大小开始时的鼠标X坐标
const startX = ref(0);
// 记录拖拽或调整大小开始时的鼠标Y坐标
const startY = ref(0);
// 记录拖拽开始时,盒子当前的左边位置
const startLeft = ref(0);
// 记录拖拽开始时,盒子当前的顶部位置
const startTop = ref(0);
// 记录调整大小开始时,盒子当前的宽度
const startWidth = ref(0);
// 记录调整大小开始时,盒子当前的高度
const startHeight = ref(0);
// 记录正在进行的调整大小操作的方向(例如:'top-left'、'top-right'、'bottom-left'、'bottom-right')
const startResizeDirection = ref('');
// 初始位置和尺寸
const left = ref(100);
const top = ref(100);
const width = ref(200);
const height = ref(150);
// 盒子父容器引用
const container = ref<HTMLDivElement | null>(null);

// 开始拖拽
const startDrag = (event) => {
  // 只在非调整框区域拖拽
  if (event.target.classList.contains('resize-handle')) return;
  isDragging.value = true;
  startX.value = event.clientX;
  startY.value = event.clientY;
  startLeft.value = left.value;
  startTop.value = top.value;
  document.addEventListener('mousemove', onDrag);
  document.addEventListener('mouseup', stopDrag);
};
// 拖拽过程中
const onDrag = (event) => {
  if (isDragging.value) {
    const dx = event.clientX - startX.value;
    const dy = event.clientY - startY.value;

    // 获取父容器的边界
    const containernew = container.value;
    const containerRect = containernew.getBoundingClientRect();

    // 计算新的位置,确保盒子不超出父容器的边界
    let newLeft = startLeft.value + dx;
    let newTop = startTop.value + dy;

    // 限制盒子在父容器内
    newLeft = Math.max(0, Math.min(containerRect.width - width.value, newLeft));
    newTop = Math.max(0, Math.min(containerRect.height - height.value, newTop));

    left.value = newLeft;
    top.value = newTop;
  }
};
// 停止拖拽
const stopDrag = () => {
  isDragging.value = false;
  document.removeEventListener('mousemove', onDrag);
  document.removeEventListener('mouseup', stopDrag);
};

// 开始调整大小
const startResize = (direction, event) => {
  isResizing.value = true;
  startResizeDirection.value = direction;
  console.log('event:', event);
  startX.value = event.clientX;
  startY.value = event.clientY;
  startWidth.value = width.value;
  startHeight.value = height.value;
  document.addEventListener('mousemove', onResize);
  document.addEventListener('mouseup', stopResize);
};

// 调整大小过程中
const onResize = (event) => {
  if (isResizing.value) {
    const dx = event.clientX - startX.value;
    const dy = event.clientY - startY.value;
    // 根据不同的调整方向更新盒子尺寸和位置
    switch (startResizeDirection.value) {
      case 'top-left':
        // 从左上角调整,改变宽度和高度,同时移动盒子位置
        width.value = Math.max(50, startWidth.value - dx);
        height.value = Math.max(50, startHeight.value - dy);
        left.value = startLeft.value + dx;
        top.value = startTop.value + dy;
        break;
      case 'top-right':
        // 从右上角调整,改变宽度和高度,同时只调整盒子上边位置
        width.value = Math.max(50, startWidth.value + dx);
        height.value = Math.max(50, startHeight.value - dy);
        top.value = startTop.value + dy;
        break;
      case 'bottom-left':
        // 从左下角调整,改变宽度和高度,同时只调整盒子左边位置
        width.value = Math.max(50, startWidth.value - dx);
        height.value = Math.max(50, startHeight.value + dy);
        left.value = startLeft.value + dx;
        break;
      case 'bottom-right':
        // 从右下角调整,改变宽度和高度
        width.value = Math.max(50, startWidth.value + dx);
        height.value = Math.max(50, startHeight.value + dy);
        break;
    }
  }
};

// 停止调整大小
const stopResize = () => {
  isResizing.value = false;
  document.removeEventListener('mousemove', onResize);
  document.removeEventListener('mouseup', stopResize);
};
</script>

<style scoped>
.container {
  position: relative;
  width: 100%;
  height: 400px;
  background-color: #f0f0f0;
  overflow: hidden;
}

.box {
  position: absolute;
  cursor: move;
  background-color: #4caf50;
  border-radius: 5px;
}

.resize-handle {
  width: 10px;
  height: 10px;
  background-color: red;
  position: absolute;
  cursor: pointer;
}

.top-left {
  top: 0;
  left: 0;
  cursor: nwse-resize;
}

.top-right {
  top: 0;
  right: 0;
  cursor: nesw-resize;
}

.bottom-left {
  bottom: 0;
  left: 0;
  cursor: nesw-resize;
}

.bottom-right {
  bottom: 0;
  right: 0;
  cursor: nwse-resize;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花归去

客官赏点吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值