增加分隔条
This commit is contained in:
208
AutoRobot/Windows/Robot/Web/src/DockLayout/ResizeBar.vue
Normal file
208
AutoRobot/Windows/Robot/Web/src/DockLayout/ResizeBar.vue
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="['resize-bar', `resize-bar-${direction}`, { 'resize-bar-hover': isHovered }]"
|
||||||
|
:style="resizeBarStyle"
|
||||||
|
@mousedown="startResize"
|
||||||
|
@mouseenter="isHovered = true"
|
||||||
|
@mouseleave="isHovered = false"
|
||||||
|
>
|
||||||
|
<div class="resize-bar-handle">
|
||||||
|
<div class="resize-bar-line"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
// Props定义
|
||||||
|
interface Props {
|
||||||
|
targetId: string
|
||||||
|
direction: 'horizontal' | 'vertical'
|
||||||
|
minSize?: number
|
||||||
|
maxSize?: number
|
||||||
|
initialSize?: number
|
||||||
|
resizeStep?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
minSize: 50,
|
||||||
|
maxSize: undefined,
|
||||||
|
initialSize: 200,
|
||||||
|
resizeStep: 10
|
||||||
|
})
|
||||||
|
|
||||||
|
// 事件定义
|
||||||
|
interface Emits {
|
||||||
|
resize: [newSize: number]
|
||||||
|
resizeStart: []
|
||||||
|
resizeEnd: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
|
// 响应式状态
|
||||||
|
const isHovered = ref(false)
|
||||||
|
const isResizing = ref(false)
|
||||||
|
const startX = ref(0)
|
||||||
|
const startY = ref(0)
|
||||||
|
const currentSize = ref(props.initialSize)
|
||||||
|
|
||||||
|
// 计算样式
|
||||||
|
const resizeBarStyle = computed(() => {
|
||||||
|
const baseStyle: Record<string, string> = {}
|
||||||
|
|
||||||
|
if (props.direction === 'horizontal') {
|
||||||
|
baseStyle.width = '4px'
|
||||||
|
baseStyle.height = '100%'
|
||||||
|
baseStyle.cursor = 'col-resize'
|
||||||
|
} else {
|
||||||
|
baseStyle.width = '100%'
|
||||||
|
baseStyle.height = '4px'
|
||||||
|
baseStyle.cursor = 'row-resize'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHovered.value || isResizing.value) {
|
||||||
|
baseStyle.backgroundColor = 'var(--dock-primary-color, #409eff)'
|
||||||
|
} else {
|
||||||
|
baseStyle.backgroundColor = 'transparent'
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseStyle
|
||||||
|
})
|
||||||
|
|
||||||
|
// 开始调整大小
|
||||||
|
const startResize = (event: MouseEvent) => {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
isResizing.value = true
|
||||||
|
startX.value = event.clientX
|
||||||
|
startY.value = event.clientY
|
||||||
|
|
||||||
|
emit('resizeStart')
|
||||||
|
|
||||||
|
// 添加全局鼠标事件监听
|
||||||
|
document.addEventListener('mousemove', handleMouseMove)
|
||||||
|
document.addEventListener('mouseup', endResize)
|
||||||
|
|
||||||
|
// 防止文本选择
|
||||||
|
document.body.style.userSelect = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理鼠标移动
|
||||||
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
|
if (!isResizing.value) return
|
||||||
|
|
||||||
|
const deltaX = event.clientX - startX.value
|
||||||
|
const deltaY = event.clientY - startY.value
|
||||||
|
|
||||||
|
let newSize = currentSize.value
|
||||||
|
|
||||||
|
if (props.direction === 'horizontal') {
|
||||||
|
newSize = Math.max(props.minSize, currentSize.value + deltaX)
|
||||||
|
if (props.maxSize) {
|
||||||
|
newSize = Math.min(props.maxSize, newSize)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newSize = Math.max(props.minSize, currentSize.value + deltaY)
|
||||||
|
if (props.maxSize) {
|
||||||
|
newSize = Math.min(props.maxSize, newSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSize !== currentSize.value) {
|
||||||
|
currentSize.value = newSize
|
||||||
|
emit('resize', newSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
startX.value = event.clientX
|
||||||
|
startY.value = event.clientY
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束调整大小
|
||||||
|
const endResize = () => {
|
||||||
|
isResizing.value = false
|
||||||
|
emit('resizeEnd')
|
||||||
|
|
||||||
|
// 移除全局鼠标事件监听
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove)
|
||||||
|
document.removeEventListener('mouseup', endResize)
|
||||||
|
|
||||||
|
// 恢复文本选择
|
||||||
|
document.body.style.userSelect = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件卸载时清理事件
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove)
|
||||||
|
document.removeEventListener('mouseup', endResize)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
getCurrentSize: () => currentSize.value,
|
||||||
|
setSize: (size: number) => {
|
||||||
|
currentSize.value = Math.max(props.minSize, Math.min(props.maxSize || Infinity, size))
|
||||||
|
},
|
||||||
|
getDirection: () => props.direction,
|
||||||
|
getTargetId: () => props.targetId
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.resize-bar {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: transparent;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar:hover {
|
||||||
|
background-color: rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar-horizontal {
|
||||||
|
cursor: col-resize;
|
||||||
|
border-left: 1px solid transparent;
|
||||||
|
border-right: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar-vertical {
|
||||||
|
cursor: row-resize;
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar-handle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar-line {
|
||||||
|
background-color: rgba(64, 158, 255, 0.3);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar-horizontal .resize-bar-line {
|
||||||
|
width: 2px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar-vertical .resize-bar-line {
|
||||||
|
width: 20px;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar:hover .resize-bar-line {
|
||||||
|
background-color: rgba(64, 158, 255, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-bar:active .resize-bar-line {
|
||||||
|
background-color: var(--dock-primary-color, #409eff);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -39,5 +39,6 @@
|
|||||||
4.1. Area的merge行为只接受一个Area参数.
|
4.1. Area的merge行为只接受一个Area参数.
|
||||||
4.1. 如果目标Area内容区为空,则将源Area内容区的子组件添加到目标Area内容区。这个源Area保存到DockLayout的的隐藏列表中。
|
4.1. 如果目标Area内容区为空,则将源Area内容区的子组件添加到目标Area内容区。这个源Area保存到DockLayout的的隐藏列表中。
|
||||||
4.2. 如果目标Area内容区已经包含一个TabPage,则将源Area的TabPage组件的每个标签页添加到目标Area的Tabpage中。这个源Area和源Area的TabPage组件保存到DockLayout的的隐藏列表中。
|
4.2. 如果目标Area内容区已经包含一个TabPage,则将源Area的TabPage组件的每个标签页添加到目标Area的Tabpage中。这个源Area和源Area的TabPage组件保存到DockLayout的的隐藏列表中。
|
||||||
|
5. 当将源Area拖动到外部边缘指示器时
|
||||||
|
5.1. 如果主区域内只有一个Area(目标区域),则压缩目标Area的空间,源区域和目标区域并排放置在主区域内。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user