Dropdown Menu 下拉菜单

基于 BrConfigProvider 实现全局主题配置,支持多方向、嵌套子菜单、自定义触发方式的企业级下拉菜单组件。

组件特性

  • 🛠️ 多方向弹出:支持向上、下、左、右四个方向弹出,自动调整以适应屏幕边缘。
  • 📋 嵌套子菜单:支持无限级嵌套的子菜单,适用于复杂的层级结构。
  • ⌨️ 快捷键支持:可为菜单项配置快捷键显示,提升键盘操作体验。
  • 🖱️ 多触发方式:支持点击(click)、悬浮(hover)、右键(contextmenu)等多种触发方式。
  • 🎨 主题定制:基于 BrConfigProvider 支持全局主题定制,同时支持 TailwindCSS 局部样式覆盖。

基础用法

最基础的下拉菜单展示。

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrButton
} from '@breezeui/vue'
</script>

<template>
  <BrDropdownMenu>
    <BrDropdownMenuTrigger as-child>
      <BrButton variant="outline">Open Menu</BrButton>
    </BrDropdownMenuTrigger>
    <BrDropdownMenuContent>
      <BrDropdownMenuItem>Profile</BrDropdownMenuItem>
      <BrDropdownMenuItem>Billing</BrDropdownMenuItem>
      <BrDropdownMenuItem>Settings</BrDropdownMenuItem>
      <BrDropdownMenuSeparator />
      <BrDropdownMenuItem>Logout</BrDropdownMenuItem>
    </BrDropdownMenuContent>
  </BrDropdownMenu>
</template>

位置

支持 alignside 属性控制弹出位置,支持 12 个不同的方向。

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrButton
} from '@breezeui/vue'

const positions = [
  [
    { label: 'Top Start', side: 'top', align: 'start' },
    { label: 'Top', side: 'top', align: 'center' },
    { label: 'Top End', side: 'top', align: 'end' },
  ],
  [
    { label: 'Right Start', side: 'right', align: 'start' },
    { label: 'Right', side: 'right', align: 'center' },
    { label: 'Right End', side: 'right', align: 'end' },
  ],
  [
    { label: 'Bottom End', side: 'bottom', align: 'end' },
    { label: 'Bottom', side: 'bottom', align: 'center' },
    { label: 'Bottom Start', side: 'bottom', align: 'start' },
  ],
  [
    { label: 'Left End', side: 'left', align: 'end' },
    { label: 'Left', side: 'left', align: 'center' },
    { label: 'Left Start', side: 'left', align: 'start' },
  ]
] as const
</script>

<template>
  <div class="flex flex-col items-center gap-4 py-8">
    <div v-for="(row, i) in positions" :key="i" class="flex flex-wrap justify-center gap-4">
      <BrDropdownMenu v-for="pos in row" :key="pos.label">
        <BrDropdownMenuTrigger as-child>
          <BrButton variant="outline" class="w-[120px]">{{ pos.label }}</BrButton>
        </BrDropdownMenuTrigger>
        <BrDropdownMenuContent :side="pos.side" :align="pos.align">
          <BrDropdownMenuItem>Option 1</BrDropdownMenuItem>
          <BrDropdownMenuItem>Option 2</BrDropdownMenuItem>
          <BrDropdownMenuItem>Option 3</BrDropdownMenuItem>
        </BrDropdownMenuContent>
      </BrDropdownMenu>
    </div>
  </div>
</template>

复杂示例

结合了图标、快捷键、分割线、嵌套子菜单、禁用状态、自定义样式的复杂应用场景。

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrDropdownMenuSub,
  BrDropdownMenuSubTrigger,
  BrDropdownMenuSubContent,
  BrButton
} from '@breezeui/vue'
import {
  Cloud,
  CreditCard,
  Github,
  Keyboard,
  LifeBuoy,
  LogOut,
  Mail,
  MessageSquare,
  Plus,
  PlusCircle,
  Settings,
  User,
  UserPlus,
} from 'lucide-vue-next'
</script>

<template>
  <BrDropdownMenu>
    <BrDropdownMenuTrigger as-child>
      <BrButton variant="outline">Complex Menu Example</BrButton>
    </BrDropdownMenuTrigger>
    <BrDropdownMenuContent class="w-56" align="end" :side-offset="8">
      <div class="px-2 py-1.5 text-sm font-normal">
        <div class="flex flex-col space-y-1">
          <p class="text-sm font-medium leading-none">breezeui</p>
          <p class="text-xs leading-none text-muted-foreground">
            breezeui@example.com
          </p>
        </div>
      </div>
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuItem shortcut="⇧⌘P">
        <User class="mr-2 h-4 w-4" />
        <span>Profile Page</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘B">
        <CreditCard class="mr-2 h-4 w-4" />
        <span>Billing Info</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘S">
        <Settings class="mr-2 h-4 w-4" />
        <span>System Settings</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘K">
        <Keyboard class="mr-2 h-4 w-4" />
        <span>Shortcut Configuration</span>
      </BrDropdownMenuItem>
      
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuSub>
        <BrDropdownMenuSubTrigger>
          <UserPlus class="mr-2 h-4 w-4" />
          <span>Invite Team Members</span>
        </BrDropdownMenuSubTrigger>
        <BrDropdownMenuSubContent>
          <BrDropdownMenuItem>
            <Mail class="mr-2 h-4 w-4" />
            <span>Via Email</span>
          </BrDropdownMenuItem>
          <BrDropdownMenuItem>
            <MessageSquare class="mr-2 h-4 w-4" />
            <span>Via SMS</span>
          </BrDropdownMenuItem>
          <BrDropdownMenuSeparator />
          <BrDropdownMenuItem>
            <PlusCircle class="mr-2 h-4 w-4" />
            <span>More Invite Options...</span>
          </BrDropdownMenuItem>
        </BrDropdownMenuSubContent>
      </BrDropdownMenuSub>
      
      <BrDropdownMenuItem>
        <Plus class="mr-2 h-4 w-4" />
        <span>New Team</span>
      </BrDropdownMenuItem>
      
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuItem>
        <Github class="mr-2 h-4 w-4" />
        <span>GitHub Repository</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem>
        <LifeBuoy class="mr-2 h-4 w-4" />
        <span>Support</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem disabled>
        <Cloud class="mr-2 h-4 w-4" />
        <span>API Service (Under Maintenance)</span>
      </BrDropdownMenuItem>
      
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuItem shortcut="⇧⌘Q" class="text-destructive focus:bg-destructive focus:text-destructive-foreground">
        <LogOut class="mr-2 h-4 w-4" />
        <span>Logout</span>
      </BrDropdownMenuItem>
    </BrDropdownMenuContent>
  </BrDropdownMenu>
</template>

嵌套子菜单与快捷键

支持多级嵌套子菜单,以及通过 shortcut 属性配置快捷键。

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrDropdownMenuSub,
  BrDropdownMenuSubTrigger,
  BrDropdownMenuSubContent,
  BrButton
} from '@breezeui/vue'
</script>

<template>
  <BrDropdownMenu>
    <BrDropdownMenuTrigger as-child>
      <BrButton variant="outline">User Action</BrButton>
    </BrDropdownMenuTrigger>
    <BrDropdownMenuContent class="w-56">
      <BrDropdownMenuItem shortcut="⇧⌘P">Profile Page</BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘B">Billing</BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘S">Settings</BrDropdownMenuItem>
      <BrDropdownMenuSeparator />
      <BrDropdownMenuSub>
        <BrDropdownMenuSubTrigger>Invite User</BrDropdownMenuSubTrigger>
        <BrDropdownMenuSubContent>
          <BrDropdownMenuItem>Via Email</BrDropdownMenuItem>
          <BrDropdownMenuItem>Via SMS</BrDropdownMenuItem>
          <BrDropdownMenuSeparator />
          <BrDropdownMenuItem>More Options...</BrDropdownMenuItem>
        </BrDropdownMenuSubContent>
      </BrDropdownMenuSub>
      <BrDropdownMenuSeparator />
      <BrDropdownMenuItem shortcut="⇧⌘Q" disabled>Logout</BrDropdownMenuItem>
    </BrDropdownMenuContent>
  </BrDropdownMenu>
</template>

自定义触发方式(悬浮/右键)

支持 clickhovercontextmenu 触发方式,可通过 trigger 属性配置。

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrButton
} from '@breezeui/vue'
</script>

<template>
  <div class="flex gap-4">
    <!-- Hover Trigger -->
    <BrDropdownMenu trigger="hover">
      <BrDropdownMenuTrigger as-child>
        <BrButton variant="outline">Hover to expand</BrButton>
      </BrDropdownMenuTrigger>
      <BrDropdownMenuContent>
        <BrDropdownMenuItem>Option 1</BrDropdownMenuItem>
        <BrDropdownMenuItem>Option 2</BrDropdownMenuItem>
      </BrDropdownMenuContent>
    </BrDropdownMenu>

    <!-- Right-click Trigger -->
    <BrDropdownMenu trigger="contextmenu">
      <BrDropdownMenuTrigger as-child>
        <div class="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm">
          Right-click in this area
        </div>
      </BrDropdownMenuTrigger>
      <BrDropdownMenuContent>
        <BrDropdownMenuItem>Refresh</BrDropdownMenuItem>
        <BrDropdownMenuItem>Save As...</BrDropdownMenuItem>
        <BrDropdownMenuSeparator />
        <BrDropdownMenuItem class="text-destructive">Delete</BrDropdownMenuItem>
      </BrDropdownMenuContent>
    </BrDropdownMenu>
  </div>
</template>

与表单集成

在表单操作或表格行操作中的典型应用。

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrButton,
  BrForm,
  BrFormItem
} from '@breezeui/vue'
import { ChevronDown } from 'lucide-vue-next'
</script>

<template>
  <BrForm>
    <BrFormItem label="Action">
      <BrDropdownMenu>
        <BrDropdownMenuTrigger as-child>
          <BrButton variant="outline">Action <ChevronDown class="ml-2 h-4 w-4" /></BrButton>
        </BrDropdownMenuTrigger>
        <BrDropdownMenuContent>
          <BrDropdownMenuItem>Edit</BrDropdownMenuItem>
          <BrDropdownMenuItem>Copy</BrDropdownMenuItem>
          <BrDropdownMenuSeparator />
          <BrDropdownMenuItem class="text-destructive">Delete</BrDropdownMenuItem>
        </BrDropdownMenuContent>
      </BrDropdownMenu>
    </BrFormItem>
  </BrForm>
</template>

主题定制

结合 BrConfigProvider,可以全局覆盖组件默认样式,例如修改圆角、悬浮态颜色、菜单阴影等。同时可以通过 TailwindCSS 局部覆盖样式。

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrButton,
  BrConfigProvider
} from '@breezeui/vue'
</script>

<template>
  <BrConfigProvider
    :theme="{
      light: {
        radius: '1rem',
        primary: '220 90% 56%',
        popover: '0 0% 100%',
        'popover-foreground': '240 10% 3.9%',
      },
      dark: {
        radius: '1rem',
        primary: '220 90% 56%',
        popover: '240 10% 3.9%',
        'popover-foreground': '0 0% 98%',
      }
    }"
  >
    <BrDropdownMenu>
      <BrDropdownMenuTrigger as-child>
        <BrButton>Custom Theme Dropdown Menu</BrButton>
      </BrDropdownMenuTrigger>
      <!-- Local Override Style Example -->
      <BrDropdownMenuContent class="border-primary/20 shadow-xl">
        <BrDropdownMenuItem class="focus:bg-primary focus:text-primary-foreground">
          Highlight Option
        </BrDropdownMenuItem>
        <BrDropdownMenuItem>Normal Option</BrDropdownMenuItem>
      </BrDropdownMenuContent>
    </BrDropdownMenu>
  </BrConfigProvider>
</template>

API 说明

BrDropdownMenu

属性类型默认值说明
open (v-model)boolean-控制菜单是否展开
defaultOpenbooleanfalse默认展开状态
dir'ltr' | 'rtl''ltr'文本阅读方向
trigger'click' | 'hover' | 'contextmenu' | Array'click'触发方式配置
openDelaynumber200悬浮触发时的展开延迟(ms)
closeDelaynumber300悬浮触发时的收起延迟(ms)

BrDropdownMenuContent

属性类型默认值说明
classany-自定义类名
side'top' | 'right' | 'bottom' | 'left''bottom'菜单弹出的方向
sideOffsetnumber4菜单距离触发器的偏移量
align'start' | 'center' | 'end''center'菜单对齐方式
alignOffsetnumber0对齐偏移量

BrDropdownMenuItem

属性类型默认值说明
disabledbooleanfalse是否禁用
shortcutstring-快捷键文本(如 "⌘K")
insetbooleanfalse是否包含左侧缩进(用于对齐图标)

BrDropdownMenuSub

用于嵌套子菜单的根容器,无需额外配置属性。

BrDropdownMenuEmpty / BrDropdownMenuLoading

用于展示空状态或加载中状态。

属性类型默认值说明
textstring'No data' / 'Loading...'提示文本