Files
JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/DockIndicator.vue
zqm 624a04ec69 独立中心指示器层级修正
- 修正 center-main-indicator z-index 从 10 更新为 10000
- 确保独立中心指示器位于 center-dock-container 上层
- 删除残留的 indicator-center 样式定义
- 更新文档中的 z-index 说明和层级结构图
- 清理代码并同步文档描述
2025-11-14 15:18:02 +08:00

957 lines
28 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 v-if="visible" class="dock-indicator" :style="indicatorStyle">
<!-- 停靠区 半透明区域框根据活动区域显示 -->
<div
v-if="activeDockZone"
class="dock-preview-area"
:style="enhancedPreviewAreaStyle"
></div>
<!-- 1. 定义可复用组件symbol封装所有渐变和路径只写一次 -->
<svg width="0" height="0" viewBox="0 0 40 40" aria-hidden="true">
<defs>
<!-- 渐变定义共用只写一次 -->
<linearGradient
id="lightGradient"
x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#DCE3F5" />
<stop offset="100%" stop-color="#B7BED1" />
</linearGradient>
<linearGradient
id="Area"
x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="#F0E2BC" />
<stop offset="100%" stop-color="#B09556" />
</linearGradient>
</defs>
<!-- 封装所有图形为 symbolid 用于后续调用 -->
<symbol id="shared-border" viewBox="0 0 40 40">
<path
fill="#61697E"
fill-rule="evenodd"
clip-rule="evenodd"
d="M0 0 L40 0 L40 40 L0 40 Z M1 1 L39 1 L39 39 L1 39 Z" />
<path
fill="#A1A9C4"
fill-rule="evenodd"
clip-rule="evenodd"
d="M1 1 L39 1 L39 39 L1 39 Z M4 5 L5 4 L35 4 L36 5 L36 35 L35 36 L5 36 L4 35 Z" />
<path
fill="#7E869C"
fill-rule="evenodd"
clip-rule="evenodd"
d="M4 5 L5 4 L35 4 L36 5 L36 35 L35 36 L5 36 L4 35 Z M6 7 L7 6 L33 6 L34 7 L34 33 L33 34 L7 34 L6 33 Z" />
<path
fill="url(#lightGradient)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M6 7 L7 6 L33 6 L34 7 L34 33 L33 34 L7 34 L6 33 Z" />
</symbol>
<symbol id="shared-icon" viewBox="0 0 40 40">
<use xlink:href="#shared-border" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M16 30 L20 26 L23 30 Z" />
</symbol>
<symbol id="shared-area" viewBox="0 0 40 40">
<use xlink:href="#shared-border" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M8 8 L32 8 L32 31 L31 32 L9 32 L8 31 Z" />
</symbol>
</svg>
<!-- 上指示根据activeDockZone状态显示和高亮 -->
<svg
v-if="!props.hideEdgeIndicators"
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-top"
:class="{ 'active': activeDockZone === 'top' }"
@mouseenter="handleMouseEnter('top')"
@mouseleave="handleMouseLeave"
>
<use xlink:href="#shared-icon" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M8 8 L32 8 L32 20 L31 21 L9 21 L8 20 Z" />
<path
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 13 L30 13 L30 19 L10 19 Z" />
</svg>
<!-- 右指示根据activeDockZone状态显示和高亮 -->
<svg
v-if="!props.hideEdgeIndicators"
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
v-if="!props.hideEdgeIndicators"
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
v-if="!props.hideEdgeIndicators"
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>
<!-- 中心区域容器包装中心指示区和中心指示器 -->
<div class="center-dock-container">
<!-- 中心指示区一直可见 -->
<svg
width="235"
height="235"
viewBox="0 0 235 235"
aria-hidden="true"
class="indicator-center-area"
:class="{ 'active': activeDockZone === 'center' }"
>
<path
fill="#636873"
fill-rule="evenodd"
clip-rule="evenodd"
d="M0 92 L83 92 L92 83 L92 0 L143 0 L143 83 L153 92 L235 92 L235 143 L153 143 L143 153 L143 235 L92 235 L92 153 L83 143 L0 143 Z" />
<path
fill="#D5DCF0"
fill-rule="evenodd"
clip-rule="evenodd"
d="M1 93 L84 93 L93 84 L93 1 L142 1 L142 84 L152 93 L234 93 L234 142 L152 142 L142 152 L142 234 L93 234 L93 152 L84 142 L1 142 Z" />
</svg>
<!-- 上区指示 -->
<svg
width="41"
height="41"
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
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 13 L30 13 L30 20 L10 20 Z" />
<path
fill="#F0F2F6"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 20 L30 20 L30 30 L10 30 Z" />
<path
d="M10 20 L30 20"
stroke="#4C5E83"
stroke-dasharray="2,2"
stroke-width="1"
fill="none" />
</svg>
<!-- 右区指示 -->
<svg
width="41"
height="41"
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
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M20 14 L30 14 L30 30 L20 30 Z" />
<path
fill="#F0F2F6"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 14 L20 14 L20 30 L10 30 Z" />
<path
d="M20 14 L20 30"
stroke="#4C5E83"
stroke-dasharray="2,2"
stroke-width="1"
fill="none" />
</svg>
<!-- 下区指示 -->
<svg
width="41"
height="41"
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
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 21 L30 21 L30 30 L10 30 Z" />
<path
fill="#F0F2F6"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 13 L30 13 L30 21 L10 21 Z" />
<path
d="M10 21 L30 21"
stroke="#4C5E83"
stroke-dasharray="2,2"
stroke-width="1"
fill="none" />
</svg>
<!-- 左区指示 -->
<svg
width="41"
height="41"
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
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 14 L20 14 L20 30 L10 30 Z" />
<path
fill="#F0F2F6"
fill-rule="evenodd"
clip-rule="evenodd"
d="M20 14 L30 14 L30 30 L20 30 Z" />
<path
d="M20 14 L20 30"
stroke="#4C5E83"
stroke-dasharray="2,2"
stroke-width="1"
fill="none" />
</svg>
<!-- 中心指示区上方指示器位于中心指示区上边缘距离上边框5像素 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-center-top"
:class="{ 'active': activeDockZone === 'center-top' }"
@mouseenter="handleMouseEnter('center-top')"
@mouseleave="handleMouseLeave"
>
<use xlink:href="#shared-icon" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M8 8 L32 8 L32 20 L31 21 L9 21 L8 20 Z" />
<path
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 13 L30 13 L30 19 L10 19 Z" />
</svg>
<!-- 中心指示区右侧指示器位于中心指示区右边缘距离右边框5像素 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-center-right"
:class="{ 'active': activeDockZone === 'center-right' }"
@mouseenter="handleMouseEnter('center-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>
<!-- 中心指示区下方指示器位于中心指示区下边缘距离下边框5像素 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-center-bottom"
:class="{ 'active': activeDockZone === 'center-bottom' }"
@mouseenter="handleMouseEnter('center-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>
<!-- 中心指示区左侧指示器位于中心指示区左边缘距离左边框5像素 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="indicator-center-left"
:class="{ 'active': activeDockZone === 'center-left' }"
@mouseenter="handleMouseEnter('center-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>
</div>
<!-- 中心指示器独立于中心区域容器位于容器正中央 -->
<svg
width="41"
height="41"
viewBox="0 0 40 40"
aria-hidden="true"
class="center-main-indicator"
:class="{ 'active': activeDockZone === 'center' }"
@mouseenter="handleMouseEnter('center')"
@mouseleave="handleMouseLeave"
>
<use xlink:href="#shared-border" />
<path
fill="#4C5E83"
fill-rule="evenodd"
clip-rule="evenodd"
d="M8 8 L32 8 L32 31 L31 32 L9 32 L8 31 Z" />
<path
fill="url(#Area)"
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 14 L30 14 L30 30 L10 30 Z" />
</svg>
</div>
</template>
<script setup>
import { computed, watch, ref, onUnmounted } from 'vue'
const props = defineProps({
visible: Boolean,
targetRect: Object,
mousePosition: Object,
hideEdgeIndicators: Boolean
})
// 创建响应式的hoveredZone状态
const hoveredZone = ref(null)
// 鼠标是否悬停在中心指示器上(用于控制中心指示区的显示)
const isCenterIndicatorHovered = ref(false)
// 延迟定时器
let mouseLeaveTimer = null
let centerLeaveTimer = null
// 处理鼠标进入指示器
const handleMouseEnter = (zone) => {
// 清除可能存在的离开定时器
if (mouseLeaveTimer) {
clearTimeout(mouseLeaveTimer)
mouseLeaveTimer = null
}
hoveredZone.value = zone
// 如果是中心指示器,设置专门的状态
if (zone === 'center') {
isCenterIndicatorHovered.value = true
}
}
// 处理鼠标离开指示器
const handleMouseLeave = () => {
// 添加短暂延迟,避免快速进出导致的闪烁
mouseLeaveTimer = setTimeout(() => {
hoveredZone.value = null
mouseLeaveTimer = null
}, 100)
// 单独处理中心指示器的离开事件,设置延迟
centerLeaveTimer = setTimeout(() => {
isCenterIndicatorHovered.value = false
centerLeaveTimer = null
}, 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) {
clearTimeout(mouseLeaveTimer)
}
if (centerLeaveTimer) {
clearTimeout(centerLeaveTimer)
}
})
// 计算指示器的样式
const indicatorStyle = computed(() => {
return {
position: 'absolute',
left: `${props.targetRect.left}px`,
top: `${props.targetRect.top}px`,
width: `${props.targetRect.width}px`,
height: `${props.targetRect.height}px`,
pointerEvents: props.visible ? 'auto' : 'none',
zIndex: 9999
}
})
// 计算活动的停靠区域 - 只有当鼠标悬停在指示器上时才返回对应的区域
const activeDockZone = computed(() => {
if (!props.visible) return null
// 只有当鼠标悬停在某个指示器上时才返回对应的区域
return hoveredZone.value
})
// 计算半透明区域框的基础样式
const previewAreaStyle = computed(() => {
if (!activeDockZone.value) return {};
const { left, top, width, height } = props.targetRect;
const threshold = 0.25;
// 根据不同的活动区域计算预览区域的样式
switch (activeDockZone.value) {
case 'top':
case 'center-top': // 中心指示区上方指示器使用与top相同的预览区域
return {
position: 'absolute',
left: `${left}px`,
top: `${top}px`,
width: `${width}px`,
height: `${height * threshold}px`
};
case 'bottom':
case 'center-bottom': // 中心指示区下方指示器使用与bottom相同的预览区域
return {
position: 'absolute',
left: `${left}px`,
top: `${top + height * (1 - threshold)}px`,
width: `${width}px`,
height: `${height * threshold}px`
};
case 'left':
case 'center-left': // 中心指示区左侧指示器使用与left相同的预览区域
return {
position: 'absolute',
left: `${left}px`,
top: `${top}px`,
width: `${width * threshold}px`,
height: `${height}px`
};
case 'right':
case 'center-right': // 中心指示区右侧指示器使用与right相同的预览区域
return {
position: 'absolute',
left: `${left + width * (1 - threshold)}px`,
top: `${top}px`,
width: `${width * threshold}px`,
height: `${height}px`
};
case 'center':
return {
position: 'absolute',
left: `${left}px`,
top: `${top}px`,
width: `${width}px`,
height: `${height}px`
};
default:
return {};
}
})
// 增强的半透明区域框样式,支持基于鼠标位置的动态计算
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'])
// 监听activeDockZone变化触发事件
watch(activeDockZone, (newZone) => {
emit('zone-active', newZone)
})
</script>
<style scoped>
.dock-indicator {
position: absolute;
box-sizing: border-box;
}
/* 半透明区域框样式 */
.dock-preview-area {
background-color: rgba(161, 169, 196, 0.3); /* 半透明背景 */
border: 2px dashed #61697E; /* 虚线边框 */
box-sizing: border-box;
z-index: 9998; /* 确保在指示器下方 */
transition: all 0.2s ease; /* 平滑过渡效果 */
pointer-events: none; /* 确保区域框不干扰鼠标事件 */
}
/* 上指示器定位在目标区域的顶端中间上边缘距dock-layout上边缘5像素 */
.indicator-top {
position: absolute;
top: 5px;
left: 50%;
transform: translateX(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 9999; /* 确保在预览区域上方 */
}
/* 右指示器定位在目标区域的右侧中间右边缘距dock-layout右边缘5像素 */
.indicator-right {
position: absolute;
top: 50%;
right: 5px;
transform: translateY(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 9999; /* 确保在预览区域上方 */
}
/* 下指示器定位在目标区域的底部中间下边缘距dock-layout下边缘5像素 */
.indicator-bottom {
position: absolute;
bottom: 5px;
left: 50%;
transform: translateX(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 9999; /* 确保在预览区域上方 */
}
/* 左指示器定位在目标区域的左侧中间左边缘距dock-layout左边缘5像素 */
.indicator-left {
position: absolute;
top: 50%;
left: 5px;
transform: translateY(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 9999; /* 确保在预览区域上方 */
}
/* 中心区域容器:包装中心指示区和中心指示器 */
.center-dock-container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999; /* 确保在预览区域上方 */
width: 235px;
height: 235px;
display: flex;
justify-content: center;
align-items: center;
}
/* 中心指示区:较大的背景区域 */
.indicator-center-area {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 1; /* 中心指示区在下层 */
}
/* 上区指示器位于中心指示区上方指示器的上方4个像素处 */
.dock-top-area {
position: absolute;
top: 51px; /* 向上偏移确保距离中心指示区上方指示器上边缘4个像素 */
left: 50%;
transform: translateX(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 左区指示器位于中心指示区左侧指示器的右侧4个像素处 */
.dock-left-area {
position: absolute;
top: 50%;
left: 51px; /* 向右偏移确保距离中心指示区左侧指示器右边缘4个像素 */
transform: translateY(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 右区指示器位于中心指示区右侧指示器的左侧4个像素处 */
.dock-right-area {
position: absolute;
top: 50%;
right: 51px; /* 向左偏移确保距离中心指示区右侧指示器左边缘4个像素 */
transform: translateY(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 下区指示器位于中心指示区下方指示器的下方4个像素处 */
.dock-bottom-area {
position: absolute;
bottom: 51px; /* 向上偏移确保距离中心指示区下方指示器下边缘4个像素 */
left: 50%;
transform: translateX(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 中心指示区上方指示器位于中心指示区上边缘距离上边框5像素 */
.indicator-center-top {
position: absolute;
top: 5px;
left: 50%;
transform: translateX(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 中心指示区右侧指示器位于中心指示区右边缘距离右边框5像素 */
.indicator-center-right {
position: absolute;
top: 50%;
right: 5px;
transform: translateY(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 中心指示区下方指示器位于中心指示区下边缘距离下边框5像素 */
.indicator-center-bottom {
position: absolute;
bottom: 5px;
left: 50%;
transform: translateX(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 中心指示区左侧指示器位于中心指示区左边缘距离左边框5像素 */
.indicator-center-left {
position: absolute;
top: 50%;
left: 5px;
transform: translateY(-50%);
opacity: 0.7; /* 默认半透明 */
transition: opacity 0.2s;
z-index: 2; /* 确保在中心指示区上方 */
}
/* 注意indicator-center 类已被移除,现在使用 center-main-indicator */
/* 独立中心指示器:位于与中心区域容器同级的正中央位置 */
.center-main-indicator {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10000; /* 确保在中心区域容器上方 */
opacity: 0.7; /* 默认半透明 */
transition: all 0.2s; /* 应用到所有属性的过渡 */
}
/* 活动状态样式 */
.indicator-top.active {
opacity: 1; /* 完全不透明 */
transform: translateX(-50%) scale(1.1); /* 保持水平居中的同时放大 */
}
.indicator-right.active {
opacity: 1; /* 完全不透明 */
transform: translateY(-50%) scale(1.1); /* 保持垂直居中的同时放大 */
}
.indicator-bottom.active {
opacity: 1; /* 完全不透明 */
transform: translateX(-50%) scale(1.1); /* 保持水平居中的同时放大 */
}
.indicator-left.active {
opacity: 1; /* 完全不透明 */
transform: translateY(-50%) scale(1.1); /* 保持垂直居中的同时放大 */
}
/* 注意indicator-center 类已被移除,现在使用 center-main-indicator */
/* 注意:.indicator-center.active 样式已被移除 */
/* 独立中心指示器的活动状态样式 */
.center-main-indicator.active {
opacity: 1; /* 完全不透明 */
transform: translate(-50%, -50%) scale(1.1); /* 保持居中位置的同时放大 */
}
/* 中心指示区内部指示器的活动状态样式 */
.indicator-center-top.active {
opacity: 1; /* 完全不透明 */
transform: translateX(-50%) scale(1.1); /* 保持水平居中的同时放大 */
}
.indicator-center-right.active {
opacity: 1; /* 完全不透明 */
transform: translateY(-50%) scale(1.1); /* 保持垂直居中的同时放大 */
}
.indicator-center-bottom.active {
opacity: 1; /* 完全不透明 */
transform: translateX(-50%) scale(1.1); /* 保持水平居中的同时放大 */
}
.indicator-center-left.active {
opacity: 1; /* 完全不透明 */
transform: translateY(-50%) scale(1.1); /* 保持垂直居中的同时放大 */
}
.indicator-center-area.active {
opacity: 1; /* 完全不透明 */
transition: all 0.2s;
}
</style>