更新DockLayout组件和相关指示器实现

This commit is contained in:
zqm
2025-11-14 10:35:22 +08:00
parent d2f47559d3
commit 05d1dd866a
3 changed files with 243 additions and 10 deletions

View File

@@ -4,7 +4,7 @@
<div
v-if="activeDockZone"
class="dock-preview-area"
:style="previewAreaStyle"
:style="enhancedPreviewAreaStyle"
></div>
<!-- 1. 定义可复用组件symbol封装所有渐变和路径只写一次 -->
<svg width="0" height="0" viewBox="0 0 40 40" aria-hidden="true">
@@ -90,6 +90,78 @@
clip-rule="evenodd"
d="M10 13 L30 13 L30 19 L10 19 Z" />
</svg>
<!-- 右指示根据activeDockZone状态显示和高亮 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-right"
:class="{ 'active': activeDockZone === 'right' }"
@mouseenter="handleMouseEnter('right')"
@mouseleave="handleMouseLeave"
>
<use xlink:href="#shared-icon" transform="rotate(90 20 20)" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M19 8 L32 8 L32 31 L31 32 L20 32 L19 31 Z" />
<path
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M21 14 L30 14 L30 30 L21 30 Z" />
</svg>
<!-- 下指示根据activeDockZone状态显示和高亮 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-bottom"
:class="{ 'active': activeDockZone === 'bottom' }"
@mouseenter="handleMouseEnter('bottom')"
@mouseleave="handleMouseLeave"
>
<use xlink:href="#shared-icon" transform="rotate(180 20 20)" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M8 19 L32 19 L32 31 L31 32 L9 32 L8 31 Z" />
<path
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 24 L30 24 L30 30 L10 30 Z" />
</svg>
<!-- 左指示根据activeDockZone状态显示和高亮 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-left"
:class="{ 'active': activeDockZone === 'left' }"
@mouseenter="handleMouseEnter('left')"
@mouseleave="handleMouseLeave"
>
<use xlink:href="#shared-icon" transform="rotate(270 20 20)" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M8 8 L21 8 L21 31 L19 32 L9 32 L8 31 Z" />
<path
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 14 L19 14 L19 30 L10 30 Z" />
</svg>
@@ -123,6 +195,9 @@
viewBox="0 0 40 40"
aria-hidden="false"
class="dock-top-area"
@mouseenter="handleSubAreaMouseEnter('top-area')"
@mouseleave="handleSubAreaMouseLeave"
@mousemove="handleSubAreaMouseMove('top-area', $event)"
>
<use xlink:href="#shared-area" />
<path
@@ -150,6 +225,9 @@
viewBox="0 0 40 40"
aria-hidden="false"
class="dock-right-area"
@mouseenter="handleSubAreaMouseEnter('right-area')"
@mouseleave="handleSubAreaMouseLeave"
@mousemove="handleSubAreaMouseMove('right-area', $event)"
>
<use xlink:href="#shared-area" />
<path
@@ -177,6 +255,9 @@
viewBox="0 0 40 40"
aria-hidden="false"
class="dock-bottom-area"
@mouseenter="handleSubAreaMouseEnter('bottom-area')"
@mouseleave="handleSubAreaMouseLeave"
@mousemove="handleSubAreaMouseMove('bottom-area', $event)"
>
<use xlink:href="#shared-area" />
<path
@@ -204,6 +285,9 @@
viewBox="0 0 40 40"
aria-hidden="false"
class="dock-left-area"
@mouseenter="handleSubAreaMouseEnter('left-area')"
@mouseleave="handleSubAreaMouseLeave"
@mousemove="handleSubAreaMouseMove('left-area', $event)"
>
<use xlink:href="#shared-area" />
<path
@@ -415,6 +499,122 @@ const handleMouseLeave = () => {
}, 100)
}
// 处理子区域鼠标进入事件
const handleSubAreaMouseEnter = (area) => {
// 清除可能存在的离开定时器
if (mouseLeaveTimer) {
clearTimeout(mouseLeaveTimer)
mouseLeaveTimer = null
}
hoveredZone.value = area
}
// 处理子区域鼠标离开事件
const handleSubAreaMouseLeave = () => {
// 添加短暂延迟,避免快速进出导致的闪烁
mouseLeaveTimer = setTimeout(() => {
hoveredZone.value = null
mouseLeaveTimer = null
}, 100)
}
// 处理子区域鼠标移动事件
const handleSubAreaMouseMove = (area, event) => {
// 更新鼠标位置信息
const rect = event.currentTarget.getBoundingClientRect()
const mouseX = event.clientX - rect.left
const mouseY = event.clientY - rect.top
// 可以在这里添加更复杂的鼠标位置计算逻辑
// 例如根据鼠标在子区域内的位置动态调整依靠区的大小
// 保持当前悬停状态
hoveredZone.value = area
}
// 检测鼠标所在的Area组件
const detectMouseArea = (mouseX, mouseY) => {
try {
// 查找所有包含Area组件的DOM元素
const areaElements = document.querySelectorAll('.vs-area')
for (let element of areaElements) {
const rect = element.getBoundingClientRect()
// 检查鼠标位置是否在当前Area元素内
if (mouseX >= rect.left && mouseX <= rect.right &&
mouseY >= rect.top && mouseY <= rect.bottom) {
return {
element: element,
rect: rect,
id: element.getAttribute('data-area-id') || element.dataset.id || 'unknown'
}
}
}
return null
} catch (error) {
console.warn('检测鼠标区域时出错:', error)
return null
}
}
// 计算基于鼠标位置的半透明依靠区样式
const computeRelianceAreaStyle = (area, zone) => {
if (!area || !props.targetRect) return {}
const { left: targetLeft, top: targetTop, width: targetWidth, height: targetHeight } = props.targetRect
const areaRect = area.rect
// 计算鼠标在Area内容区内的相对位置
const mouseRelativeX = props.mousePosition.x - areaRect.left
const mouseRelativeY = props.mousePosition.y - areaRect.top
// 根据不同区域和鼠标位置计算依靠区
const threshold = 0.3
switch (zone) {
case 'top-area':
return {
position: 'absolute',
left: `${targetLeft}px`,
top: `${targetTop}px`,
width: `${targetWidth}px`,
height: `${targetHeight * threshold}px`
}
case 'bottom-area':
return {
position: 'absolute',
left: `${targetLeft}px`,
top: `${targetTop + targetHeight * (1 - threshold)}px`,
width: `${targetWidth}px`,
height: `${targetHeight * threshold}px`
}
case 'left-area':
return {
position: 'absolute',
left: `${targetLeft}px`,
top: `${targetTop}px`,
width: `${targetWidth * threshold}px`,
height: `${targetHeight}px`
}
case 'right-area':
return {
position: 'absolute',
left: `${targetLeft + targetWidth * (1 - threshold)}px`,
top: `${targetTop}px`,
width: `${targetWidth * threshold}px`,
height: `${targetHeight}px`
}
default:
return {}
}
}
// 清理定时器
onUnmounted(() => {
if (mouseLeaveTimer) {
@@ -446,7 +646,7 @@ const activeDockZone = computed(() => {
return hoveredZone.value
})
// 计算半透明区域框的样式
// 计算半透明区域框的基础样式
const previewAreaStyle = computed(() => {
if (!activeDockZone.value) return {};
@@ -504,6 +704,27 @@ const previewAreaStyle = computed(() => {
}
})
// 增强的半透明区域框样式,支持基于鼠标位置的动态计算
const enhancedPreviewAreaStyle = computed(() => {
if (!activeDockZone.value) return {};
// 如果是子区域指示器,使用增强的计算逻辑
if (activeDockZone.value.includes('-area')) {
// 检测鼠标所在的Area组件
const mouseArea = detectMouseArea(props.mousePosition.x, props.mousePosition.y)
// 使用基于鼠标位置的计算逻辑
const relianceStyle = computeRelianceAreaStyle(mouseArea, activeDockZone.value)
// 合并基础样式和增强样式
const basicStyle = previewAreaStyle.value
return { ...basicStyle, ...relianceStyle }
}
// 对于非子区域指示器,使用原有的计算逻辑
return previewAreaStyle.value
})
// 定义事件
const emit = defineEmits(['zone-active'])