Skip to content

下拉菜单 Dropdown

赞助

向下弹出的列表

何时使用

当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单,可在列表中进行选择,并执行相应的命令。

  • 用于收罗一组命令操作
  • Select 用于选择,而 Dropdown 是命令集合

基本使用

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown :menus="basicMenus">
    <a @click.prevent>
      Hover me
      <DownOutlined />
    </a>
  </Dropdown>
</template>

触发方式

默认是移入触发菜单,可以点击触发。

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const triggerMenus: DropdownMenuOption[] = [
  { key: '0', label: '1st menu item', href: 'http://www.alipay.com/' },
  { key: '1', label: '2nd menu item', href: 'http://www.taobao.com/' },
  { type: 'divider' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown :menus="triggerMenus" trigger="click">
    <a @click.prevent>
      Click me
      <DownOutlined />
    </a>
  </Dropdown>
</template>

触发方式可组合成数组,移入展开、点击收起。

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown :menus="basicMenus" :trigger="['hover', 'click']">
    <a @click.prevent>
      Hover or Click me
      <DownOutlined />
    </a>
  </Dropdown>
</template>

右键菜单

默认是移入触发菜单,可以点击鼠标右键触发。


Show Code
vue
<script setup lang="ts">
import type { DropdownMenuOption } from 'vue-amazing-ui'
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown :menus="basicMenus" trigger="contextmenu">
    <div style="width: 240px; height: 200px; line-height: 200px; text-align: center; color: #777; background: #f7f7f7; border-radius: 8px">
      Right Click on here
    </div>
  </Dropdown>
</template>

触发事件

点击菜单项后会触发事件,用户可以通过相应的菜单项 key 进行不同的操作。

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownKey, DropdownMenuOption } from 'vue-amazing-ui'
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
function onMenuClick(key: DropdownKey | undefined, option: DropdownMenuOption) {
  console.log(`Click on item ${key}`, option)
}
</script>
<template>
  <Dropdown :menus="basicMenus" @menu-click="onMenuClick">
    <a @click.prevent>
      Hover me, Click menu item
      <DownOutlined />
    </a>
  </Dropdown>
</template>

弹出位置

支持 6 个弹出位置。


Show Code
vue
<script setup lang="ts">
import type { DropdownMenuOption } from 'vue-amazing-ui'
const placements = ['topLeft', 'top', 'topRight', 'bottomLeft', 'bottom', 'bottomRight']
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown v-for="p in placements" :key="p" :menus="basicMenus" :placement="p">
    <Button>{{ p }}</Button>
  </Dropdown>
</template>

箭头

Show Code
vue
<script setup lang="ts">
import type { DropdownMenuOption } from 'vue-amazing-ui'
const placements = ['topLeft', 'top', 'topRight', 'bottomLeft', 'bottom', 'bottomRight']
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown v-for="p in placements" :key="p" :menus="basicMenus" :placement="p" arrow>
    <Button>{{ p }}</Button>
  </Dropdown>
</template>

箭头指向

设置 arrow{ pointAtCenter: true } 后,箭头将指向目标元素的中心。


Show Code
vue
<script setup lang="ts">
import type { DropdownMenuOption } from 'vue-amazing-ui'
const placements = ['topLeft', 'top', 'topRight', 'bottomLeft', 'bottom', 'bottomRight']
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown
    v-for="p in placements"
    :key="p"
    :menus="basicMenus"
    :placement="p"
    :arrow="{ pointAtCenter: true }"
  >
    <Button>{{ p }}</Button>
  </Dropdown>
</template>

其他元素

分割线和不可用菜单项。

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const itemMenus: DropdownMenuOption[] = [
  { key: '0', label: '1st menu item', href: 'http://www.alipay.com/', target: '_blank' },
  { key: '1', label: '2nd menu item', href: 'http://www.taobao.com/', target: '_blank' },
  { type: 'divider' },
  { key: '3', label: '3rd menu item(disabled)', disabled: true }
]
</script>
<template>
  <Dropdown :menus="itemMenus">
    <a @click.prevent>
      Hover me
      <DownOutlined />
    </a>
  </Dropdown>
</template>

菜单分组

支持把菜单项进行分组,分组子项相对分组标题缩进显示。

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const groupMenus: DropdownMenuOption[] = [
  {
    type: 'group',
    label: 'Group 1',
    children: [
      { key: '1-1', label: 'Option 1-1' },
      { key: '1-2', label: 'Option 1-2' }
    ]
  },
  {
    type: 'group',
    label: 'Group 2',
    children: [
      { key: '2-1', label: 'Option 2-1' },
      { key: '2-2', label: 'Option 2-2' }
    ]
  }
]
</script>
<template>
  <Dropdown :menus="groupMenus">
    <a @click.prevent>
      Grouped menu
      <DownOutlined />
    </a>
  </Dropdown>
</template>

危险项

设置菜单项的 danger 属性可标记为危险项。


Show Code
vue
<script setup lang="ts">
import type { DropdownMenuOption } from 'vue-amazing-ui'
const dangerMenus: DropdownMenuOption[] = [
  { key: '1', label: 'Edit' },
  { key: '2', label: 'Duplicate' },
  { type: 'divider' },
  { key: '3', label: 'Delete', danger: true }
]
</script>
<template>
  <Dropdown :menus="dangerMenus" trigger="click">
    <Button>Danger Menu</Button>
  </Dropdown>
</template>

菜单项加载中

添加菜单项的 loading 属性即可让该菜单项进入加载状态。


Show Code
vue
<script setup lang="ts">
import type { DropdownMenuOption } from 'vue-amazing-ui'
const loadingMenus: DropdownMenuOption[] = [
  { key: '1', label: 'Submit and continue', loading: true },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown :menus="loadingMenus" trigger="click">
    <Button>Loading Menu</Button>
  </Dropdown>
</template>

多级菜单

传入的菜单里有多个层级。

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const subMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  {
    key: '3',
    label: 'sub menu',
    children: [
      { key: '3-1', label: '3rd menu item' },
      { key: '3-2', label: '4th menu item' }
    ]
  },
  {
    key: '4',
    label: 'disabled sub menu',
    disabled: true,
    children: [
      { key: '4-1', label: '5d menu item' },
      { key: '4-2', label: '6th menu item' }
    ]
  }
]
</script>
<template>
  <Dropdown :menus="subMenus">
    <a @click.prevent>
      Cascading menu
      <DownOutlined />
    </a>
  </Dropdown>
</template>

菜单层级支持递归渲染,可嵌套任意层级。

Show Code
vue
<script setup lang="ts">
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const nestedMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  {
    key: '2',
    label: 'sub menu',
    children: [
      { key: '2-1', label: '2nd menu item' },
      {
        key: '2-2',
        label: 'nested sub menu',
        children: [
          { key: '2-2-1', label: '3rd menu item' },
          { key: '2-2-2', label: '4th menu item' }
        ]
      }
    ]
  }
]
</script>
<template>
  <Dropdown :menus="nestedMenus">
    <a @click.prevent>
      Nested menu
      <DownOutlined />
    </a>
  </Dropdown>
</template>

禁用

菜单不可用。


Show Code
vue
<script setup lang="ts">
import type { DropdownMenuOption } from 'vue-amazing-ui'
const basicMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item' },
  { key: '2', label: '2nd menu item' },
  { key: '3', label: '3rd menu item' }
]
</script>
<template>
  <Dropdown :menus="basicMenus" disabled>
    <Button>Disabled Menu</Button>
  </Dropdown>
</template>

菜单隐藏方式

默认是点击关闭菜单,可以关闭此功能。

Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownKey, DropdownMenuOption } from 'vue-amazing-ui'
const keepOpenMenus: DropdownMenuOption[] = [
  { key: '1', label: 'Clicking me will not close the menu.' },
  { key: '2', label: 'Clicking me will not close the menu also.' },
  { key: '3', label: 'Clicking me will close the menu' }
]
const visible = ref<boolean>(false)
function onKeepOpenOpenChange(val: boolean) {
  if (val) {
    visible.value = true
  }
}
function onKeepOpenMenuClick(key: DropdownKey | undefined) {
  if (key === '3') {
    visible.value = false
  }
}
</script>
<template>
  <Dropdown
    :menus="keepOpenMenus"
    :open="visible"
    @menu-click="onKeepOpenMenuClick"
    @open-change="onKeepOpenOpenChange"
  >
    <a @click.prevent>
      Hover me
      <DownOutlined />
    </a>
  </Dropdown>
</template>

带下拉框的按钮

左边是按钮,右边是额外的相关功能菜单。可设置 icon 属性来修改右边的图标。


Show Code
vue
<script setup lang="ts">
import { h } from 'vue'
import { DownOutlined, UserOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const iconMenus: DropdownMenuOption[] = [
  { key: '1', label: '1st menu item', icon: h(UserOutlined) },
  { key: '2', label: '2nd menu item', icon: h(UserOutlined) },
  { key: '3', label: '3rd item', icon: h(UserOutlined) }
]
function onButtonClick(e: MouseEvent) {
  console.log('click left button', e)
}
function onMenuClick(key, option) {
  console.log(`Click on item ${key}`, option)
}
</script>
<template>
  <DropdownButton :menus="iconMenus" @click="onButtonClick" @menu-click="onMenuClick">
    Dropdown
  </DropdownButton>
  <DropdownButton :menus="iconMenus">
    Dropdown
    <template #icon>
      <UserOutlined />
    </template>
  </DropdownButton>
  <DropdownButton :menus="iconMenus" disabled @click="onButtonClick"> Dropdown </DropdownButton>
  <Dropdown :menus="iconMenus">
    <Button>
      Button
      <DownOutlined />
    </Button>
  </Dropdown>
</template>

加载中状态

添加 loading 属性即可让按钮处于加载状态,最后两个按钮演示点击后进入加载状态。


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import { DownOutlined } from '@ant-design/icons-vue'
import type { DropdownMenuOption } from 'vue-amazing-ui'
const buttonMenus: DropdownMenuOption[] = [{ key: '1', label: 'Submit and continue' }]
const loading1 = ref<boolean>(false)
const loading2 = ref<boolean>(false)
function enterLoading1() {
  loading1.value = true
  setTimeout(() => {
    loading1.value = false
  }, 6000)
}
function enterLoading2() {
  loading2.value = true
  setTimeout(() => {
    loading2.value = false
  }, 6000)
}
</script>
<template>
  <Space direction="vertical">
    <DropdownButton :menus="buttonMenus" type="primary" loading>Submit</DropdownButton>
    <DropdownButton :menus="buttonMenus" type="primary" size="small" loading>Submit</DropdownButton>
    <DropdownButton :menus="buttonMenus" type="primary" :loading="loading1" @click="enterLoading1">
      Submit
    </DropdownButton>
    <DropdownButton :menus="buttonMenus" :loading="loading2" @click="enterLoading2">
      Submit
      <template #icon>
        <DownOutlined />
      </template>
    </DropdownButton>
  </Space>
</template>

自定义浮层内容

使用 overlay 插槽自定义下拉内容,与 menus 配置二选一。


Show Code
vue
<script setup lang="ts">
import { SmileOutlined } from '@ant-design/icons-vue'
</script>
<template>
  <Dropdown trigger="click">
    <Button>Custom Overlay</Button>
    <template #overlay>
      <div style="display: flex; align-items: center; gap: 8px; padding: 12px 16px">
        <SmileOutlined />
        <span>自定义内容</span>
      </div>
    </template>
  </Dropdown>
</template>

APIs

参数说明类型默认值
open
v-model
下拉菜单是否展开booleanundefined
menus菜单项配置数据 (配置式),与 overlay 插槽二选一MenuOption[][]
placement下拉菜单弹出位置'topLeft' | 'top' | 'topRight' | 'bottomLeft' | 'bottom' | 'bottomRight''bottomLeft'
arrow是否显示下拉箭头;传 { pointAtCenter: true } 时箭头指向触发器中心boolean | DropdownArrowOptionsfalse
disabled菜单是否禁用booleanfalse
trigger触发下拉行为的方式,可传数组组合DropdownTrigger | DropdownTrigger[]'hover'
flip下拉菜单被浏览器窗口或最近可滚动父元素遮挡时自动调整弹出位置booleantrue
mouseEnterDelay移入触发器显示下拉菜单的延迟时间,单位 mstrigger'hover' 时生效number100
mouseLeaveDelay移出触发器隐藏下拉菜单的延迟时间,单位 mstrigger'hover' 时生效number100
transitionDuration下拉菜单动画的过渡持续时间,单位 msnumber200
destroyOnHide隐藏后是否卸载下拉菜单 DOM:离开动画结束后卸载,再次显示时重新创建并重新定位booleanfalse
to下拉菜单挂载的容器节点,可选:元素标签名 (例如 'body') 或者元素本身,false 会待在原地;不传时就近挂载到 Modal / Drawer / Dialog 等承载层内容容器(无承载层则 bodystring | HTMLElement | falseundefined
overlayClassName下拉菜单根元素的类名stringundefined
overlayStyle下拉菜单根元素的样式CSSProperties{}
zIndex下拉菜单层级,优先级最高(未传时使用默认层级或 ConfigProviderbaseZIndex 分配)numberundefined
类型说明
'hover' | 'click' | 'contextmenu'分别对应移入、点击、右键触发;传入数组可组合多种触发方式
名称说明类型默认值
pointAtCenter箭头是否指向触发器中心booleanfalse
名称说明类型默认值
key菜单项唯一标识string | numberundefined
label菜单项显示文本stringundefined
icon菜单项图标VNodeundefined
disabled是否禁用booleanfalse
danger是否为危险项(红色文本)booleanfalse
loading是否加载中booleanfalse
href链接地址,存在时菜单项渲染为 a 标签stringundefined
target链接打开方式,href 存在时生效'_self' | '_blank''_self'
type菜单项类型:菜单项 | 分割线 | 分组'item' | 'divider' | 'group''item'
children子菜单(多级菜单)或分组子项,支持任意层级递归MenuOption[]undefined
参数说明类型默认值
open
v-model
下拉菜单是否展开booleanundefined
menus菜单项配置数据 (配置式),与 overlay 插槽二选一MenuOption[][]
type按钮类型,同 Button'default' | 'primary' | 'danger' | 'dashed' | 'text' | 'link''default'
size按钮尺寸,同 Button'small' | 'middle' | 'large''middle'
icon右侧下拉按钮图标(默认为省略号),插槽形态请用 #icon 插槽VNodeundefined
placement下拉菜单弹出位置'topLeft' | 'top' | 'topRight' | 'bottomLeft' | 'bottom' | 'bottomRight''bottomRight'
arrow是否显示下拉箭头;传 { pointAtCenter: true } 时箭头指向触发器中心boolean | DropdownArrowOptionsfalse
disabled菜单是否禁用(左按钮和右按钮同时禁用)booleanfalse
loading左侧按钮加载状态booleanfalse
trigger触发下拉行为的方式,可传数组组合DropdownTrigger | DropdownTrigger[]'hover'
mouseEnterDelay移入触发按钮显示下拉菜单的延迟时间,单位 mstrigger'hover' 时生效number100
mouseLeaveDelay移出触发按钮隐藏下拉菜单的延迟时间,单位 mstrigger'hover' 时生效number100
destroyOnHide隐藏后是否卸载下拉菜单 DOMbooleanfalse
to下拉菜单挂载的容器节点,可选:元素标签名 (例如 'body') 或者元素本身,false 会待在原地;不传时就近挂载到 Modal / Drawer / Dialog 等承载层内容容器(无承载层则 bodystring | HTMLElement | falseundefined
overlayClassName下拉菜单根元素的类名stringundefined
overlayStyle下拉菜单根元素的样式CSSProperties{}

Events

名称说明类型
openChange下拉菜单展开收起时的回调(点击菜单项导致的收起不触发)(open: boolean) => void
menuClick点击菜单项时的回调(disabledloading 项不触发)(key: string | number | undefined, option: MenuOption) => void
名称说明类型
click点击左侧按钮时的回调(e: MouseEvent) => void
openChange下拉菜单展开收起时的回调(点击菜单项导致的收起不触发)(open: boolean) => void
menuClick点击菜单项时的回调(disabledloading 项不触发)(key: string | number | undefined, option: MenuOption) => void

Slots

名称说明用法
default触发器内容v-slot:default
overlay自定义下拉浮层内容(与 menus 配置二选一)v-slot:overlay
label自定义菜单项显示文本v-slot:label="{ option }"
名称说明用法
default左侧按钮内容v-slot:default
overlay自定义下拉浮层内容(与 menus 配置二选一)v-slot:overlay
icon自定义右侧下拉按钮图标(优先于 icon 属性)v-slot:icon
label自定义菜单项显示文本v-slot:label="{ option }"

Released under the MIT License.