Dropdown 组件是向下弹窗列表。点击或移入触电,会出现一个下拉菜单,可以在列表中进行选择,并执行相应的命令。
二次封装对外暴露参数
<script lang="ts" setup>
const props = defineProps({
// 是否确认
popconfirm: Boolean,
// 触发下拉的行为,默认鼠标右击触发
trigger: {
type: [Array] as PropType<('contextmenu' | 'click' | 'hover')[]>,
default: () => {
return ['contextmenu'];
},
},
// 下拉菜单
dropMenuList: {
type: Array as PropType<(DropMenu & Recordable)[]>,
default: () => [],
},
// 当前选中的菜单项 key 数组
selectedKeys: {
type: Array as PropType<string[]>,
default: () => [],
},
})
</script>
dropdown 组件
dropdown 组件使用 ant-design-vue 库支持 overlay 插槽插入菜单列表,默认插槽插入显示信息。
<!-- src/components/Dropdown/src/Dropdown.vue -->
<template>
<a-dropdown :trigger="trigger" v-bind="$attrs">
<span>
<slot></slot>
</span>
<template #overlay>
<a-menu :selectedKeys="selectedKeys">
<template v-for="item in dropMenuList" :key="`${item.event}`">
<a-menu-item
v-bind="getAttr(item.event)"
@click="handleClickMenu(item)"
:disabled="item.disabled"
>
<Icon :icon="item.icon" v-if="item.icon" />
<span class="ml-1">{{ item.text }}</span>
</a-menu-item>
<a-menu-divider v-if="item.divider" :key="`d-${item.event}`" />
</template>
</a-menu>
</template>
</a-dropdown>
</template>
菜单项点击事件
const emit = defineEmits(['menuEvent'])
function handleClickMenu(item: DropMenu) {
const { event } = item
const menu = props.dropMenuList.find(item => item.event === event)
emit('menuEvent', menu)
item.onClick?.()
}
useTabDropdown 的设计
useTabDropdown 方法对外暴露属性和方法,如下:
// src/layout/default/tabs/useTabDropdown.ts
export function useTabDropdown(tabContentProps, getIsTabs) {
// 获取下拉菜单
const getDropMenuList = computed(() => {})
// 选中菜单项
function handleContextMenu() {}
// 处理菜单事件
function handleMenuEvent() {}
return { getDropMenuList, handleMenuEvent, handleContextMenu }
}
useTabDropdown 的实现
import { useTabs } from '/@/hooks/web/useTabs'
const getDropMenuList = computed(() => {
const dropMenuList = [
{ icon: 'ion:reload-sharp', event: MenuEventEnum.REFRESH_PAGE, text: '重新加载', disabled: refreshDisabled, },
{ icon: 'clarity:close-line', event: MenuEventEnum.CLOSE_CURRENT, text: '关闭标签', disabled: !!meta ?.affix || disabled, divider: true, },
{ icon: 'line-md:arrow-close-left', event: MenuEventEnum.CLOSE_LEFT, text: '关闭左侧标签页', disabled: closeLeftDisabled, divider: false, },
{ icon: 'line-md:arrow-close-right', event: MenuEventEnum.CLOSE_RIGHT, text: '关闭右侧标签页', disabled: closeRightDisabled, divider: true, },
{ icon: 'dashicons:align-center', event: MenuEventEnum.CLOSE_OTHER, text: '关闭其他标签页', disabled: disabled || !isCurItem, },
{ icon: 'clarity:minus-line', event: MenuEventEnum.CLOSE_ALL, text: '关闭全部标签页', disabled: disabled, },
]
return dropMenuList
})
const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs();
function handleMenuEvent(menu) {
const { event } = menu
switch (event) {
case MenuEventEnum.REFRESH_PAGE:
refreshPage();
break;
case MenuEventEnum.CLOSE_CURRENT:
close(tabContentProps.tabItem);
break;
case MenuEventEnum.CLOSE_LEFT:
closeLeft();
break;
case MenuEventEnum.CLOSE_RIGHT:
closeRight();
break;
case MenuEventEnum.CLOSE_OTHER:
closeOther();
break;
case MenuEventEnum.CLOSE_ALL:
closeAll();
break;
}
}
function handleContextMenu(tabItem) {
return (e) => {
if (!tabItem) {
return
}
e?.preventDefault()
const index = tabStore.getTabList.findIndex(tab => tab.path === tabItem.path)
// 后续可用于菜单列表 disabled 属性处理
state.current = tabItem
state.currentIndex = index
}
}
组件使用
<!-- src/layouts/default/tabs/components/TabContent.vue -->
<template>
<Dropdown
:dropMenuList="getDropMenuList"
:trigger="getTrigger"
placement="bottom"
overlayClassName="multiple-tabs__dropdown"
@menu-event="handleMenuEvent"
>
<div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="getIsTabs">
<span class="ml-1">{{ getTitle }}</span>
</div>
<span :class="`${prefixCls}__extra-quick`" v-else @click="handleContext">
<Icon icon="ion:chevron-down" />
</span>
</Dropdown>
</template>
<script lang="ts">
import { Dropdown } from '/@/components/Dropdown/index'
import { useTabDropdown } from '../useTabDropdown'
export default defineComponent({
components: { Dropdown },
setup(props) {
const getIsTabs = computed(() => !props.isExtra)
const getTrigger = computed((): ('contextmenu' | 'click' | 'hover') =>
unref(getIsTabs) ? ['contextmenu'] : ['click']
)
const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown(props, getIsTabs)
function handleContext(e) {
props.tabItem && handleContextMenu(props.tabItem)(e)
}
return { getIsTabs, getTrigger, getDropMenuList, handleMenuEvent }
}
})
</script>