Files
klp-oa/klp-ui/src/components/DragResizeBox/index.vue
砂糖 e1fbb7805f feat(CoilSelector): 添加可拖拽库位视图和品质列显示
refactor(WarehouseInterlaced): 修复props格式问题
fix(DuGeTag): 修正电话号码格式
2026-03-11 10:47:49 +08:00

231 lines
6.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="drag-resize-container" ref="containerRef">
<!-- 可拖拽调整的元素 -->
<div
class="draggable-element"
ref="elementRef"
:style="{
left: `${position.x}px`,
top: `${position.y}px`,
width: `${size.width}px`,
height: `${size.height}px`
}"
@mousedown="startDrag"
>
<!-- 元素内容区 -->
<div class="element-content">
<slot>可拖拽调整的元素</slot>
</div>
<!-- 右下角调整大小的控制点 -->
<div class="resize-handle" @mousedown="startResize"></div>
</div>
</div>
</template>
<script>
export default {
name: 'DragResizeBox',
props: {
// 初始位置
initPosition: {
type: Object,
default: () => ({ x: 100, y: 100 })
},
// 初始尺寸
initSize: {
type: Object,
default: () => ({ width: 200, height: 150 })
},
// 移除容器尺寸限制保留prop但默认值改为屏幕尺寸
containerSize: {
type: Object,
default: () => ({
width: window.innerWidth,
height: window.innerHeight
})
},
// 元素最小尺寸
minSize: {
type: Object,
default: () => ({ width: 100, height: 80 })
}
},
data() {
return {
// 当前位置
position: { x: 0, y: 0 },
// 当前尺寸
size: { width: 0, height: 0 },
// 拖拽状态
isDragging: false,
// 调整大小状态
isResizing: false,
// 鼠标初始位置
startMouse: { x: 0, y: 0 },
// 元素初始状态
startState: { x: 0, y: 0, width: 0, height: 0 }
};
},
mounted() {
// 初始化位置和尺寸
this.position = { ...this.initPosition };
this.size = { ...this.initSize };
// 监听全局鼠标移动和松开事件
document.addEventListener('mousemove', this.handleMouseMove);
document.addEventListener('mouseup', this.handleMouseUp);
// 监听窗口大小变化,更新屏幕尺寸
window.addEventListener('resize', this.updateScreenSize);
},
beforeDestroy() {
// 移除全局事件监听,防止内存泄漏
document.removeEventListener('mousemove', this.handleMouseMove);
document.removeEventListener('mouseup', this.handleMouseUp);
window.removeEventListener('resize', this.updateScreenSize);
},
methods: {
/**
* 更新屏幕尺寸(窗口大小变化时)
*/
updateScreenSize() {
this.containerSize = {
width: window.innerWidth,
height: window.innerHeight
};
},
/**
* 开始拖拽(移动位置)
*/
startDrag(e) {
// 阻止事件冒泡,避免和调整大小冲突
if (e.target.classList.contains('resize-handle')) return;
this.isDragging = true;
// 记录鼠标初始位置
this.startMouse = { x: e.clientX, y: e.clientY };
// 记录元素初始位置
this.startState = {
x: this.position.x,
y: this.position.y,
width: this.size.width,
height: this.size.height
};
// 更改鼠标样式
document.body.style.cursor = 'move';
},
/**
* 开始调整大小
*/
startResize(e) {
e.stopPropagation(); // 阻止事件冒泡
this.isResizing = true;
// 记录鼠标初始位置
this.startMouse = { x: e.clientX, y: e.clientY };
// 记录元素初始尺寸
this.startState = {
x: this.position.x,
y: this.position.y,
width: this.size.width,
height: this.size.height
};
// 更改鼠标样式
document.body.style.cursor = 'se-resize';
},
/**
* 处理鼠标移动
*/
handleMouseMove(e) {
if (this.isDragging) {
// 计算鼠标移动的偏移量
const dx = e.clientX - this.startMouse.x;
const dy = e.clientY - this.startMouse.y;
// 核心修改:移除容器边界限制,仅限制不超出屏幕左侧/顶部(右侧/底部可任意移动)
this.position.x = Math.max(0, this.startState.x + dx);
this.position.y = Math.max(0, this.startState.y + dy);
// 触发位置变化事件
this.$emit('position-change', { ...this.position });
}
if (this.isResizing) {
// 计算鼠标移动的偏移量
const dx = e.clientX - this.startMouse.x;
const dy = e.clientY - this.startMouse.y;
// 调整大小仅限制最小尺寸,不限制屏幕边界
this.size.width = Math.max(this.minSize.width, this.startState.width + dx);
this.size.height = Math.max(this.minSize.height, this.startState.height + dy);
// 触发尺寸变化事件
this.$emit('size-change', { ...this.size });
}
},
/**
* 处理鼠标松开
*/
handleMouseUp() {
// 重置状态
this.isDragging = false;
this.isResizing = false;
// 恢复鼠标样式
document.body.style.cursor = 'default';
// 触发结束事件
this.$emit('drag-end', { position: { ...this.position }, size: { ...this.size } });
}
}
};
</script>
<style scoped>
/* 容器样式:改为全屏且无视觉样式 */
.drag-resize-container {
position: fixed; /* 固定定位覆盖整个屏幕 */
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none; /* 容器不拦截鼠标事件,不影响页面其他元素 */
box-sizing: border-box;
}
/* 可拖拽元素样式fixed定位确保基于屏幕移动 */
.draggable-element {
position: fixed;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
user-select: none; /* 禁止文本选中 */
box-sizing: border-box;
overflow: hidden;
pointer-events: auto; /* 元素本身响应鼠标事件 */
z-index: 9999; /* 确保元素在最上层 */
}
/* 元素内容区 */
.element-content {
height: calc(100% - 20px);
padding: 10px;
cursor: move;
}
/* 调整大小控制点 */
.resize-handle {
position: absolute;
right: 0;
bottom: 0;
width: 20px;
height: 20px;
background-color: #1e88e5;
cursor: se-resize;
border-top-left-radius: 4px;
}
/* 控制点hover效果 */
.resize-handle:hover {
background-color: #1976d2;
}
</style>