<template>
<div id="resizableDiv" ref="draggableBox" :style="{ top: top + 'px', left: left + 'px' }" @mousedown="startDrag" class="resizable-div">
<div class="resize-handle top" data-direction="top"></div>
<div class="resize-handle right" data-direction="right"></div>
<div class="resize-handle bottom" data-direction="bottom"></div>
<div class="resize-handle left" data-direction="left"></div>
<div class="content">拖拽区域的内容</div>
</div>
</template>
<script setup>
import {onMounted, onUnmounted, ref} from "vue";
const draggableBox = ref(null);
const top = ref(200); // 元素距离顶部的位置
const left = ref(200); // 元素距离左边的位置
let isDragging = false; // 是否正在拖拽
let offsetX = 0; // 鼠标点击点距离元素左上角的偏移
let offsetY = 0; // 鼠标点击点距离元素左上角的偏移
// 鼠标按下时开始拖拽
const startDrag = (event) => {
isDragging = true;
offsetX = event.clientX - left.value;
offsetY = event.clientY - top.value;
// 添加mousemove和mouseup事件监听
document.addEventListener('mousemove', handleDrag);
document.addEventListener('mouseup', stopDrag);
};
// 鼠标移动时拖拽元素
const handleDrag = (event) => {
if (isDragging) {
left.value = event.clientX - offsetX;
top.value = event.clientY - offsetY;
// 限制元素不超出可视区域
const maxX = window.innerWidth - 20; // 假设可视区域宽度为窗口宽度减去100
const maxY = window.innerHeight - 20; // 假设可视区域高度为窗口高度减去100
left.value = Math.min(maxX, Math.max(0, left.value));
if (left.value > window.innerWidth - draggableBox.value.clientWidth - 5) {
left.value = window.innerWidth - draggableBox.value.clientWidth - 5
}
top.value = Math.min(maxY, Math.max(0, top.value));
if (top.value > window.innerHeight - draggableBox.value.clientHeight - 5) {
top.value = window.innerHeight - draggableBox.value.clientHeight - 5
}
}
};
// 鼠标松开时停止拖拽
const stopDrag = () => {
isDragging = false;
document.removeEventListener('mousemove', handleDrag);
document.removeEventListener('mouseup', stopDrag);
};
onUnmounted(() => {
// 在组件销毁前移除事件监听等资源
document.removeEventListener('mousemove', handleDrag);
document.removeEventListener('mouseup', stopDrag);
});
onMounted(() => {
const resizableDiv = document.getElementById('resizableDiv');
const resizeHandles = resizableDiv.querySelectorAll('.resize-handle');
let isResizing = false;
let currentHandle;
resizeHandles.forEach(handle => {
handle.addEventListener('mousedown', (e) => {
isResizing = true;
currentHandle = e.target.dataset.direction;
e.stopPropagation()
});
});
document.addEventListener('mousemove', (e) => {
if (!isResizing) return;
if (currentHandle) {
if (currentHandle === 'right') {
resizableDiv.style.width = e.clientX - resizableDiv.getBoundingClientRect().left + 'px';
} else if (currentHandle === 'bottom') {
resizableDiv.style.height = e.clientY - resizableDiv.getBoundingClientRect().top + 'px';
} else if (currentHandle === 'left') {
const originalWidth = resizableDiv.getBoundingClientRect().right - resizableDiv.getBoundingClientRect().left;
const newWidth = resizableDiv.getBoundingClientRect().right - e.clientX;
resizableDiv.style.left = e.clientX + 'px';
resizableDiv.style.width = originalWidth + newWidth + 'px';
} else if (currentHandle === 'top') {
const originalHeight = resizableDiv.getBoundingClientRect().bottom - resizableDiv.getBoundingClientRect().top;
const newHeight = resizableDiv.getBoundingClientRect().bottom - e.clientY;
resizableDiv.style.top = e.clientY + 'px';
resizableDiv.style.height = originalHeight + newHeight + 'px';
}
}
});
document.addEventListener('mouseup', () => {
isResizing = false;
currentHandle = null;
});
})
</script>
<style lang="less">
.resizable-div {
position: absolute;
width: 200px;
height: 200px;
border: 2px solid #333;
user-select: none;
display: flex;
flex-direction: column;
}
.resize-handle {
position: absolute;
background-color: #007bff;
cursor: pointer;
}
.resize-handle.top {
width: 100%;
height: 2px;
left: 0;
top: -2px;
}
.resize-handle.right {
height: 100%;
width: 2px;
top: 0;
right: -2px;
}
.resize-handle.bottom {
width: 100%;
height: 2px;
left: 0;
bottom: -2px;
}
.resize-handle.left {
height: 100%;
width: 2px;
top: 0;
left: -2px;
}
.content {
flex-grow: 1;
background-color: #f0f0f0;
padding: 10px;
}
</style>
Vue3 实现元素拖拽,缩放功能
最新推荐文章于 2024-05-17 04:51:24 发布