Dropdown 下拉菜单实现标签页的相关操作

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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值