实现Area组件拖拽功能和边界限制,完善初始居中定位
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
:style="areaStyle"
|
||||
>
|
||||
<!-- 顶部标题栏 -->
|
||||
<div v-if="showTitleBar" class="vs-title-bar">
|
||||
<div v-if="showTitleBar" class="vs-title-bar" :class="{ 'cursor-move': !isMaximized }" @mousedown="onDragStart">
|
||||
<div class="vs-title-left">
|
||||
<div class="vs-app-icon" aria-label="AppIcon">
|
||||
<svg class="vs-icon" viewBox="0 0 22.4 22.4" aria-hidden="true">
|
||||
@@ -57,7 +57,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, computed, defineEmits, ref } from 'vue'
|
||||
import { defineProps, computed, defineEmits, ref, onMounted } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
id: { type: String, required: true },
|
||||
@@ -85,6 +85,14 @@ const originalPosition = ref({
|
||||
top: props.top
|
||||
})
|
||||
|
||||
// 拖拽相关状态
|
||||
const isDragging = ref(false)
|
||||
const dragStartPos = ref({ x: 0, y: 0 })
|
||||
const areaStartPos = ref({ x: 0, y: 0 })
|
||||
|
||||
// 父容器引用
|
||||
const parentContainer = ref(null)
|
||||
|
||||
// 根据本地状态计算是否最大化
|
||||
const isMaximized = computed(() => localState.value === '最大化' || localState.value === 'maximized')
|
||||
|
||||
@@ -98,7 +106,9 @@ const areaStyle = computed(() => {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 100
|
||||
zIndex: 100,
|
||||
margin: 0,
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +129,69 @@ const areaStyle = computed(() => {
|
||||
return style
|
||||
})
|
||||
|
||||
const emit = defineEmits(['close', 'update:WindowState'])
|
||||
const emit = defineEmits(['close', 'update:WindowState', 'update:position'])
|
||||
|
||||
// 拖拽开始
|
||||
const onDragStart = (e) => {
|
||||
// 最大化状态下不允许拖拽
|
||||
if (isMaximized.value) return
|
||||
|
||||
isDragging.value = true
|
||||
dragStartPos.value = {
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
}
|
||||
areaStartPos.value = {
|
||||
x: originalPosition.value.left || 0,
|
||||
y: originalPosition.value.top || 0
|
||||
}
|
||||
|
||||
// 添加全局事件监听
|
||||
document.addEventListener('mousemove', onDragMove)
|
||||
document.addEventListener('mouseup', onDragEnd)
|
||||
|
||||
// 防止文本选择
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
// 拖拽移动
|
||||
const onDragMove = (e) => {
|
||||
if (!isDragging.value) return
|
||||
|
||||
// 计算移动距离
|
||||
const deltaX = e.clientX - dragStartPos.value.x
|
||||
const deltaY = e.clientY - dragStartPos.value.y
|
||||
|
||||
// 计算新位置
|
||||
let newLeft = areaStartPos.value.x + deltaX
|
||||
let newTop = areaStartPos.value.y + deltaY
|
||||
|
||||
// 如果有父容器引用,应用边界限制
|
||||
if (parentContainer.value) {
|
||||
const parentRect = parentContainer.value.getBoundingClientRect()
|
||||
const areaWidth = originalPosition.value.width
|
||||
const areaHeight = originalPosition.value.height
|
||||
|
||||
// 确保不超出父容器边界
|
||||
newLeft = Math.max(0, Math.min(newLeft, parentRect.width - areaWidth))
|
||||
newTop = Math.max(0, Math.min(newTop, parentRect.height - areaHeight))
|
||||
}
|
||||
|
||||
// 更新位置
|
||||
originalPosition.value.left = newLeft
|
||||
originalPosition.value.top = newTop
|
||||
|
||||
// 通知父组件位置变化
|
||||
emit('update:position', { left: newLeft, top: newTop })
|
||||
}
|
||||
|
||||
// 拖拽结束
|
||||
const onDragEnd = () => {
|
||||
isDragging.value = false
|
||||
// 移除全局事件监听
|
||||
document.removeEventListener('mousemove', onDragMove)
|
||||
document.removeEventListener('mouseup', onDragEnd)
|
||||
}
|
||||
|
||||
const onToggleMaximize = () => {
|
||||
const next = isMaximized.value ? '正常' : '最大化'
|
||||
@@ -128,6 +200,11 @@ const onToggleMaximize = () => {
|
||||
}
|
||||
|
||||
const onClose = () => emit('close')
|
||||
|
||||
// 组件挂载后获取父容器引用
|
||||
onMounted(() => {
|
||||
parentContainer.value = document.querySelector('.dock-layout') || window
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user