|
|
|
|
@ -1,22 +1,31 @@
|
|
|
|
|
<template>
|
|
|
|
|
<!-- 下拉菜单容器组件,设置相对定位和z-index,用于包裹触发元素和下拉菜单 -->
|
|
|
|
|
<!-- 绑定点击事件切换下拉状态,鼠标悬停/离开事件,以及点击外部关闭下拉菜单 -->
|
|
|
|
|
<div
|
|
|
|
|
class="ob-dropdown relative z-50"
|
|
|
|
|
@click="toggle"
|
|
|
|
|
@mouseover="hoverHandler"
|
|
|
|
|
@mouseleave="leaveHandler"
|
|
|
|
|
v-click-away="onClickAway">
|
|
|
|
|
class="ob-dropdown relative z-50"
|
|
|
|
|
@click="toggle"
|
|
|
|
|
@mouseover="hoverHandler"
|
|
|
|
|
@mouseleave="leaveHandler"
|
|
|
|
|
v-click-away="onClickAway">
|
|
|
|
|
<!-- 插槽:用于插入触发下拉菜单的元素(如按钮、文本等) -->
|
|
|
|
|
<slot />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
// 导入Vue相关API
|
|
|
|
|
import { defineComponent, provide, reactive, ref, toRefs, watch } from 'vue'
|
|
|
|
|
// 导入下拉菜单状态管理
|
|
|
|
|
import { useDropdownStore } from '@/stores/dropdown'
|
|
|
|
|
// 导入通用状态管理
|
|
|
|
|
import { useCommonStore } from '@/stores/common'
|
|
|
|
|
|
|
|
|
|
// 定义下拉菜单组件
|
|
|
|
|
export default defineComponent({
|
|
|
|
|
// 声明组件可触发的事件:命令事件(用于子项点击传递命令)
|
|
|
|
|
emits: ['command'],
|
|
|
|
|
name: 'Dropdown',
|
|
|
|
|
// 接收的props参数:是否支持hover触发下拉
|
|
|
|
|
props: {
|
|
|
|
|
hover: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
@ -24,42 +33,68 @@ export default defineComponent({
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
setup(props, { emit }) {
|
|
|
|
|
// 获取通用状态管理实例(用于判断是否为移动设备)
|
|
|
|
|
const commonStore = useCommonStore()
|
|
|
|
|
// 将hover props转为ref对象,便于响应式监听
|
|
|
|
|
const mouseHover = toRefs(props).hover
|
|
|
|
|
// 获取下拉菜单状态管理实例
|
|
|
|
|
const dropdownStore = useDropdownStore()
|
|
|
|
|
// 用于标识当前下拉菜单的事件ID(防止多个下拉菜单冲突)
|
|
|
|
|
const eventId = ref(0)
|
|
|
|
|
// 共享状态:控制下拉菜单的显示/隐藏(通过provide注入给子组件)
|
|
|
|
|
let sharedState: { active: boolean } = reactive({
|
|
|
|
|
active: false
|
|
|
|
|
})
|
|
|
|
|
// 向子组件提供共享状态(DropdownMenu会使用该状态控制显示)
|
|
|
|
|
provide('sharedState', sharedState)
|
|
|
|
|
|
|
|
|
|
// 监听下拉菜单状态管理中的命令名称变化
|
|
|
|
|
watch(
|
|
|
|
|
() => dropdownStore.commandName,
|
|
|
|
|
(newName, oldName) => {
|
|
|
|
|
const name = newName ? newName : oldName
|
|
|
|
|
if (eventId.value === dropdownStore.uid) emit('command', name)
|
|
|
|
|
}
|
|
|
|
|
() => dropdownStore.commandName,
|
|
|
|
|
(newName, oldName) => {
|
|
|
|
|
// 确定当前命令名称(优先取新值,无新值则用旧值)
|
|
|
|
|
const name = newName ? newName : oldName
|
|
|
|
|
// 当事件ID匹配时,触发command事件传递命令名称
|
|
|
|
|
if (eventId.value === dropdownStore.uid) emit('command', name)
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 切换下拉菜单显示状态的方法(点击触发)
|
|
|
|
|
const toggle = () => {
|
|
|
|
|
// 当菜单未激活时,设置唯一标识ID
|
|
|
|
|
if (!sharedState.active) eventId.value = dropdownStore.setUid()
|
|
|
|
|
// 非hover模式下,点击切换显示状态
|
|
|
|
|
if (!mouseHover.value) sharedState.active = !sharedState.active
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 点击外部区域关闭下拉菜单的方法
|
|
|
|
|
const onClickAway = () => {
|
|
|
|
|
// 非hover模式且非移动设备时,点击外部关闭菜单并重置事件ID
|
|
|
|
|
if (!mouseHover.value && !commonStore.isMobile) {
|
|
|
|
|
sharedState.active = false
|
|
|
|
|
eventId.value = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 鼠标悬停时的处理方法
|
|
|
|
|
const hoverHandler = () => {
|
|
|
|
|
// 当菜单未激活时,设置唯一标识ID
|
|
|
|
|
if (!sharedState.active) eventId.value = dropdownStore.setUid()
|
|
|
|
|
// hover模式下,鼠标悬停显示菜单
|
|
|
|
|
if (mouseHover.value) sharedState.active = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 鼠标离开时的处理方法
|
|
|
|
|
const leaveHandler = () => {
|
|
|
|
|
// hover模式下,鼠标离开隐藏菜单并重置事件ID
|
|
|
|
|
if (mouseHover.value) {
|
|
|
|
|
sharedState.active = false
|
|
|
|
|
eventId.value = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 暴露方法供模板使用
|
|
|
|
|
return { toggle, onClickAway, hoverHandler, leaveHandler }
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
</script>
|