761 lines
22 KiB
Vue
761 lines
22 KiB
Vue
<template>
|
||
<div v-if="visible" class="dock-indicator" :style="indicatorStyle">
|
||
<!-- 停靠区 半透明区域框:根据活动区域显示 -->
|
||
<div
|
||
v-if="activeDockZone"
|
||
class="dock-preview-area"
|
||
:style="previewAreaStyle"
|
||
></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>
|
||
|
||
<!-- 封装所有图形为 symbol(id 用于后续调用) -->
|
||
<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>
|
||
|
||
<!-- 上区指示 -->
|
||
<svg
|
||
width="41"
|
||
height="41"
|
||
viewBox="0 0 40 40"
|
||
aria-hidden="false"
|
||
>
|
||
<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
|
||
d="M10 20 L30 20"
|
||
stroke="#4C5E83"
|
||
stroke-dasharray="2,2"
|
||
stroke-width="1"
|
||
fill="none" />
|
||
<path
|
||
fill="#F0F2F6"
|
||
fill-rule="evenodd"
|
||
clip-rule="evenodd"
|
||
d="M10 21 L30 21 L30 30 L10 30 Z" />
|
||
</svg>
|
||
|
||
<!-- 右区指示 -->
|
||
<svg
|
||
width="41"
|
||
height="41"
|
||
viewBox="0 0 40 40"
|
||
aria-hidden="false"
|
||
>
|
||
<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
|
||
d="M20 14 L20 30"
|
||
stroke="#4C5E83"
|
||
stroke-dasharray="2,2"
|
||
stroke-width="1"
|
||
fill="none" />
|
||
<path
|
||
fill="#F0F2F6"
|
||
fill-rule="evenodd"
|
||
clip-rule="evenodd"
|
||
d="M10 14 L19 14 L19 30 L10 30 Z" />
|
||
</svg>
|
||
|
||
<!-- 下区指示 -->
|
||
<svg
|
||
width="41"
|
||
height="41"
|
||
viewBox="0 0 40 40"
|
||
aria-hidden="false"
|
||
>
|
||
<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
|
||
d="M10 21 L30 21"
|
||
stroke="#4C5E83"
|
||
stroke-dasharray="2,2"
|
||
stroke-width="1"
|
||
fill="none" />
|
||
<path
|
||
fill="#F0F2F6"
|
||
fill-rule="evenodd"
|
||
clip-rule="evenodd"
|
||
d="M10 13 L30 13 L30 20 L10 20 Z" />
|
||
</svg>
|
||
|
||
<!-- 左区指示 -->
|
||
<svg
|
||
width="41"
|
||
height="41"
|
||
viewBox="0 0 40 40"
|
||
aria-hidden="false"
|
||
>
|
||
<use xlink:href="#shared-area" />
|
||
<path
|
||
fill="url(#Area)"
|
||
fill-rule="evenodd"
|
||
clip-rule="evenodd"
|
||
d="M10 14 L19 14 L19 30 L10 30 Z" />
|
||
<path
|
||
d="M20 14 L20 30"
|
||
stroke="#4C5E83"
|
||
stroke-dasharray="2,2"
|
||
stroke-width="1"
|
||
fill="none" />
|
||
<path
|
||
fill="#F0F2F6"
|
||
fill-rule="evenodd"
|
||
clip-rule="evenodd"
|
||
d="M20 14 L30 14 L30 30 L20 30 Z" />
|
||
</svg>
|
||
|
||
<!-- 上指示:根据activeDockZone状态显示和高亮 -->
|
||
<svg
|
||
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
|
||
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>
|
||
|
||
<!-- 中心区域容器:包装中心指示区和中心指示器 -->
|
||
<div class="center-dock-container">
|
||
<!-- 中心指示区:一直可见 -->
|
||
<svg
|
||
width="185"
|
||
height="185"
|
||
viewBox="0 0 185 185"
|
||
aria-hidden="true"
|
||
class="indicator-center-area"
|
||
:class="{ 'active': activeDockZone === 'center' }"
|
||
>
|
||
<path
|
||
fill="#636873"
|
||
fill-rule="evenodd"
|
||
clip-rule="evenodd"
|
||
d="M0 72 L63 72 L72 63 L72 0 L113 0 L113 63 L123 72 L185 72 L185 113 L123 113 L113 123 L113 185 L72 185 L72 123 L63 113 L0 113 Z" />
|
||
<path
|
||
fill="#D5DCF0"
|
||
fill-rule="evenodd"
|
||
clip-rule="evenodd"
|
||
d="M1 73 L64 73 L73 64 L73 1 L112 1 L112 64 L122 73 L184 73 L184 112 L122 112 L112 122 L112 184 L73 184 L73 122 L64 112 L1 112 Z" />
|
||
</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>
|
||
|
||
<!-- 中心指示器:根据activeDockZone状态显示和高亮,添加鼠标事件处理 -->
|
||
<svg
|
||
width="41"
|
||
height="41"
|
||
viewBox="0 0 40 40"
|
||
aria-hidden="true"
|
||
class="indicator-center"
|
||
: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>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, watch, ref, onUnmounted } from 'vue'
|
||
|
||
// Props定义
|
||
const props = defineProps({
|
||
// 是否可见
|
||
visible: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 目标区域的位置和大小信息
|
||
targetRect: {
|
||
type: Object,
|
||
default: () => ({
|
||
left: 0,
|
||
top: 0,
|
||
width: 0,
|
||
height: 0
|
||
})
|
||
},
|
||
// 鼠标位置
|
||
mousePosition: {
|
||
type: Object,
|
||
default: () => ({
|
||
x: 0,
|
||
y: 0
|
||
})
|
||
}
|
||
})
|
||
|
||
// 鼠标悬停在哪个指示器上
|
||
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)
|
||
}
|
||
|
||
// 清理定时器
|
||
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 + width * threshold}px`,
|
||
top: `${top + height * threshold}px`,
|
||
width: `${width * (1 - 2 * threshold)}px`,
|
||
height: `${height * (1 - 2 * threshold)}px`
|
||
};
|
||
default:
|
||
return {};
|
||
}
|
||
})
|
||
|
||
// 定义事件
|
||
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: 185px;
|
||
height: 185px;
|
||
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; /* 中心指示区在下层 */
|
||
}
|
||
|
||
/* 中心指示区上方指示器:位于中心指示区上边缘,距离上边框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 {
|
||
position: relative;
|
||
z-index: 2; /* 确保在中心指示区上方 */
|
||
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.active {
|
||
opacity: 1; /* 完全不透明 */
|
||
transform: 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> |