实现功能:当Area内容区只有一个Panel时,拖动Panel标题栏可以移动Area

This commit is contained in:
zqm
2025-11-04 11:05:12 +08:00
parent 8ec95d63f5
commit 9762ef3b1a
2 changed files with 105 additions and 2 deletions

View File

@@ -37,6 +37,9 @@
@maximize="onMaximize" @maximize="onMaximize"
@close="onClosePanel(area.id, panel.id)" @close="onClosePanel(area.id, panel.id)"
@toggleToolbar="onToggleToolbar" @toggleToolbar="onToggleToolbar"
@dragStart="onPanelDragStart(area.id, $event)"
@dragMove="onPanelDragMove(area.id, $event)"
@dragEnd="onPanelDragEnd"
/> />
</Area> </Area>
@@ -67,6 +70,14 @@ const dockLayoutRef = ref(null)
// 区域ID计数器 // 区域ID计数器
let areaIdCounter = 1 let areaIdCounter = 1
// Panel拖拽相关状态
const panelDragState = ref({
isDragging: false,
currentAreaId: null,
startClientPos: { x: 0, y: 0 },
startAreaPos: { x: 0, y: 0 }
})
// 添加新的浮动面板 // 添加新的浮动面板
const addFloatingPanel = () => { const addFloatingPanel = () => {
// 获取父容器尺寸以计算居中位置 // 获取父容器尺寸以计算居中位置
@@ -169,6 +180,59 @@ const onToggleToolbar = (id) => {
} }
} }
// Panel拖拽开始
const onPanelDragStart = (areaId, event) => {
const area = floatingAreas.value.find(a => a.id === areaId)
// 只有当Area中只有一个Panel时才允许通过Panel标题栏移动Area
if (area && area.panels.length === 1) {
panelDragState.value.isDragging = true
panelDragState.value.currentAreaId = areaId
panelDragState.value.startClientPos = {
x: event.clientX,
y: event.clientY
}
panelDragState.value.startAreaPos = {
x: area.x,
y: area.y
}
}
}
// Panel拖拽移动
const onPanelDragMove = (areaId, event) => {
if (panelDragState.value.isDragging && panelDragState.value.currentAreaId === areaId) {
const area = floatingAreas.value.find(a => a.id === areaId)
if (area) {
// 计算移动距离
const deltaX = event.clientX - panelDragState.value.startClientPos.x
const deltaY = event.clientY - panelDragState.value.startClientPos.y
// 计算新位置
let newLeft = panelDragState.value.startAreaPos.x + deltaX
let newTop = panelDragState.value.startAreaPos.y + deltaY
// 确保不超出父容器边界
if (dockLayoutRef.value) {
const parentRect = dockLayoutRef.value.getBoundingClientRect()
// 严格边界检查
newLeft = Math.max(0, Math.min(newLeft, parentRect.width - area.width))
newTop = Math.max(0, Math.min(newTop, parentRect.height - area.height))
}
// 更新位置
area.x = newLeft
area.y = newTop
}
}
}
// Panel拖拽结束
const onPanelDragEnd = () => {
panelDragState.value.isDragging = false
panelDragState.value.currentAreaId = null
}
// 暴露方法给父组件 // 暴露方法给父组件
defineExpose({ defineExpose({
addFloatingPanel addFloatingPanel

View File

@@ -3,7 +3,11 @@
:style="{ top: y + 'px', left: x + 'px', width: width + 'px', height: height + 'px' }"> :style="{ top: y + 'px', left: x + 'px', width: width + 'px', height: height + 'px' }">
<div class="flex flex-col h-full"> <div class="flex flex-col h-full">
<!-- 标题栏 --> <!-- 标题栏 -->
<div class="title-bar h-6 bg-[#435d9c] text-white px-2 flex items-center justify-between select-none"> <div class="title-bar h-6 bg-[#435d9c] text-white px-2 flex items-center justify-between select-none cursor-move"
@mousedown="onDragStart"
@mousemove="onDragMove"
@mouseup="onDragEnd"
@mouseleave="onDragEnd">
<div class="flex items-center"> <div class="flex items-center">
<span class="text-xs">{{ title }}</span> <span class="text-xs">{{ title }}</span>
</div> </div>
@@ -98,7 +102,7 @@ const props = defineProps({
}); });
// 定义事件 // 定义事件
const emit = defineEmits(['toggleCollapse', 'maximize', 'close', 'toggleToolbar']); const emit = defineEmits(['toggleCollapse', 'maximize', 'close', 'toggleToolbar', 'dragStart', 'dragMove', 'dragEnd']);
// 事件处理函数 // 事件处理函数
const onToggleCollapse = () => { const onToggleCollapse = () => {
@@ -116,6 +120,41 @@ const onClose = () => {
const onToggleToolbar = () => { const onToggleToolbar = () => {
emit('toggleToolbar', props.id); emit('toggleToolbar', props.id);
}; };
// 拖拽相关状态
let isDragging = false;
// 拖拽开始
const onDragStart = (e) => {
// 只有当点击的是标题栏区域(不是按钮)时才触发拖拽
if (!e.target.closest('.title-bar-buttons') && !e.target.closest('button')) {
isDragging = true;
emit('dragStart', {
clientX: e.clientX,
clientY: e.clientY
});
// 防止文本选择
e.preventDefault();
}
};
// 拖拽移动
const onDragMove = (e) => {
if (isDragging) {
emit('dragMove', {
clientX: e.clientX,
clientY: e.clientY
});
}
};
// 拖拽结束
const onDragEnd = () => {
if (isDragging) {
isDragging = false;
emit('dragEnd');
}
};
</script> </script>
<style scoped> <style scoped>