<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-11
1120

09-11
2168

12-07
1026

12-27
838

07-20
471
