Dropdown 下拉菜单
可展开/收起的菜单,用于展示链接或操作列表。
TIP
菜单层与触发器之间的小三角(Popper 箭头)默认不显示;需要时设置 show-arrow。
基础用法
悬停在触发区域上展开更多操作。
触发器由默认插槽渲染,菜单内容由 dropdown 插槽渲染。默认在悬停时展开,无需点击。
Dropdown List
vue
<template>
<u-dropdown>
<span class="u-dropdown-link">
Dropdown List
<u-icon class="u-icon--right">
<arrow-down />
</u-icon>
</span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item disabled>Action 4</u-dropdown-item>
<u-dropdown-item divided>Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</template>
<script lang="ts" setup>
import { ArrowDown } from '@uniboot/icons-vue'
</script>
<style scoped>
.example-showcase .u-dropdown-link {
cursor: pointer;
color: var(--u-color-primary);
display: flex;
align-items: center;
}
</style>
隐藏源代码
弹出位置
支持多种方位。
使用 placement 控制菜单相对触发器的位置。
vue
<template>
<div class="flex flex-wrap items-center gap-4">
<u-dropdown placement="top-start">
<u-button> topStart </u-button>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>The Action 1st</u-dropdown-item>
<u-dropdown-item>The Action 2nd</u-dropdown-item>
<u-dropdown-item>The Action 3rd</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown placement="top">
<u-button> top </u-button>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>The Action 1st</u-dropdown-item>
<u-dropdown-item>The Action 2nd</u-dropdown-item>
<u-dropdown-item>The Action 3rd</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown placement="top-end">
<u-button> topEnd </u-button>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>The Action 1st</u-dropdown-item>
<u-dropdown-item>The Action 2nd</u-dropdown-item>
<u-dropdown-item>The Action 3rd</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown placement="bottom-start">
<u-button> bottomStart </u-button>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>The Action 1st</u-dropdown-item>
<u-dropdown-item>The Action 2nd</u-dropdown-item>
<u-dropdown-item>The Action 3rd</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown placement="bottom">
<u-button> bottom </u-button>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>The Action 1st</u-dropdown-item>
<u-dropdown-item>The Action 2nd</u-dropdown-item>
<u-dropdown-item>The Action 3rd</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown placement="bottom-end">
<u-button> bottomEnd </u-button>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>The Action 1st</u-dropdown-item>
<u-dropdown-item>The Action 2nd</u-dropdown-item>
<u-dropdown-item>The Action 3rd</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</div>
</template>
隐藏源代码
触发器
使用按钮作为触发器。
split-button 将触发区域拆为按钮组:左侧为普通按钮,右侧为下拉触发。若需在第三、四项之间加分隔线,给第四项设置 divided 即可。
vue
<template>
<div class="flex flex-wrap items-center">
<u-dropdown>
<u-button type="primary">
Dropdown List<u-icon class="u-icon--right"><arrow-down /></u-icon>
</u-button>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item>Action 4</u-dropdown-item>
<u-dropdown-item>Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown split-button type="primary" @click="handleClick">
Dropdown List
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item divided>Action 4</u-dropdown-item>
<u-dropdown-item>Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</div>
</template>
<script lang="ts" setup>
import { ArrowDown } from '@uniboot/icons-vue'
const handleClick = () => {
// eslint-disable-next-line no-alert
alert('button click')
}
</script>
<style scoped>
.example-showcase .u-dropdown + .u-dropdown {
margin-left: 15px;
}
.example-showcase .u-dropdown-link {
cursor: pointer;
color: var(--u-color-primary);
display: flex;
align-items: center;
}
</style>
隐藏源代码
触发方式
点击或悬停展开。
使用 trigger,默认为 hover。
hover to trigger
Dropdown List
click to trigger
Dropdown List
right click to trigger
Dropdown List
vue
<template>
<u-row class="block-col-2">
<u-col :span="8">
<span class="demonstration">hover to trigger</span>
<u-dropdown>
<span class="u-dropdown-link">
Dropdown List<u-icon class="u-icon--right"><arrow-down /></u-icon>
</span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item :icon="Plus">Action 1</u-dropdown-item>
<u-dropdown-item :icon="CirclePlusFilled">
Action 2
</u-dropdown-item>
<u-dropdown-item :icon="CirclePlus">Action 3</u-dropdown-item>
<u-dropdown-item :icon="Check">Action 4</u-dropdown-item>
<u-dropdown-item :icon="CircleCheck">Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</u-col>
<u-col :span="8">
<span class="demonstration">click to trigger</span>
<u-dropdown trigger="click">
<span class="u-dropdown-link">
Dropdown List<u-icon class="u-icon--right"><arrow-down /></u-icon>
</span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item :icon="Plus">Action 1</u-dropdown-item>
<u-dropdown-item :icon="CirclePlusFilled">
Action 2
</u-dropdown-item>
<u-dropdown-item :icon="CirclePlus">Action 3</u-dropdown-item>
<u-dropdown-item :icon="Check">Action 4</u-dropdown-item>
<u-dropdown-item :icon="CircleCheck">Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</u-col>
<u-col :span="8">
<span class="demonstration">right click to trigger</span>
<u-dropdown trigger="contextmenu">
<span class="u-dropdown-link">
Dropdown List<u-icon class="u-icon--right"><arrow-down /></u-icon>
</span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item :icon="Plus">Action 1</u-dropdown-item>
<u-dropdown-item :icon="CirclePlusFilled">
Action 2
</u-dropdown-item>
<u-dropdown-item :icon="CirclePlus">Action 3</u-dropdown-item>
<u-dropdown-item :icon="Check">Action 4</u-dropdown-item>
<u-dropdown-item :icon="CircleCheck">Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</u-col>
</u-row>
</template>
<script lang="ts" setup>
import {
ArrowDown,
Check,
CircleCheck,
CirclePlus,
CirclePlusFilled,
Plus,
} from '@uniboot/icons-vue'
</script>
<style scoped>
.block-col-2 .demonstration {
display: block;
color: var(--u-text-color-secondary);
font-size: 14px;
margin-bottom: 20px;
}
.block-col-2 .u-dropdown-link {
display: flex;
align-items: center;
}
</style>
隐藏源代码
点击后是否关闭
通过 hide-on-click 控制点击菜单项后是否收起。
默认点击菜单项会关闭;将 hide-on-click 设为 false 可保持展开。
Dropdown List
vue
<template>
<u-dropdown :hide-on-click="false">
<span class="u-dropdown-link">
Dropdown List<u-icon class="u-icon--right"><arrow-down /></u-icon>
</span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item disabled>Action 4</u-dropdown-item>
<u-dropdown-item divided>Action 5</u-dropdown-item>
<u-dropdown-item divided>Action 6</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</template>
<script lang="ts" setup>
import { ArrowDown } from '@uniboot/icons-vue'
</script>
<style scoped>
.example-showcase .u-dropdown + .u-dropdown {
margin-left: 15px;
}
.example-showcase .u-dropdown-link {
cursor: pointer;
color: var(--u-color-primary);
display: flex;
align-items: center;
}
</style>
隐藏源代码
command 事件
点击菜单项会触发事件,参数由该项的 command 传入。
Dropdown List
vue
<template>
<u-dropdown @command="handleCommand">
<span class="u-dropdown-link">
Dropdown List<u-icon class="u-icon--right"><arrow-down /></u-icon>
</span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item command="a">Action 1</u-dropdown-item>
<u-dropdown-item command="b">Action 2</u-dropdown-item>
<u-dropdown-item command="c">Action 3</u-dropdown-item>
<u-dropdown-item command="d" disabled>Action 4</u-dropdown-item>
<u-dropdown-item command="e" divided>Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</template>
<script lang="ts" setup>
import { UMessage } from 'uniboot-ui'
import { ArrowDown } from '@uniboot/icons-vue'
const handleCommand = (command: string | number | object) => {
UMessage(`click on item ${command}`)
}
</script>
<style scoped>
.example-showcase .u-dropdown-link {
cursor: pointer;
color: var(--u-color-primary);
display: flex;
align-items: center;
}
</style>
隐藏源代码
手动打开/关闭
可调用实例上的 handleOpen、handleClose。
open(close) the Dropdown list2 will close(open) the Dropdown List1.
Dropdown List1
Dropdown List2
vue
<template>
<div style="font-size: 14px">
<p>open(close) the Dropdown list2 will close(open) the Dropdown List1.</p>
</div>
<div style="margin: 15px">
<u-button @click="showClick">show</u-button>
</div>
<u-dropdown ref="dropdown1" trigger="contextmenu" style="margin-right: 30px">
<span class="u-dropdown-link"> Dropdown List1 </span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item disabled>Action 4</u-dropdown-item>
<u-dropdown-item divided>Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown trigger="contextmenu" @visible-change="handleVisible2">
<span class="u-dropdown-link"> Dropdown List2 </span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item disabled>Action 4</u-dropdown-item>
<u-dropdown-item divided>Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { DropdownInstance } from 'uniboot-ui'
const dropdown1 = ref<DropdownInstance>()
function handleVisible2(visible: any) {
if (!dropdown1.value) return
if (visible) {
dropdown1.value.handleClose()
} else {
dropdown1.value.handleOpen()
}
}
function showClick() {
if (!dropdown1.value) return
dropdown1.value.handleOpen()
}
</script>
<style scoped>
.example-showcase .u-dropdown-link {
cursor: pointer;
color: var(--u-color-primary);
display: flex;
align-items: center;
}
</style>
隐藏源代码
尺寸
除默认尺寸外,还提供 large、default、small。
使用 size 属性。
vue
<template>
<u-dropdown size="large" split-button type="primary">
Large
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item>Action 4</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown split-button type="primary">
Default
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item>Action 4</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
<u-dropdown size="small" split-button type="primary">
Small
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item>Action 1</u-dropdown-item>
<u-dropdown-item>Action 2</u-dropdown-item>
<u-dropdown-item>Action 3</u-dropdown-item>
<u-dropdown-item>Action 4</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</template>
<style scoped>
.example-showcase .u-dropdown + .u-dropdown {
margin-left: 15px;
}
</style>
隐藏源代码
树形菜单
支持通过 Dropdown-Item 的 children 属性定义多级菜单,悬停可逐级展开。
树形菜单
vue
<template>
<u-dropdown trigger="click" placement="bottom-start">
<span class="u-dropdown-link"> 树形菜单 </span>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item
v-for="item in menus"
:key="item.label"
:command="item.command"
:children="item.children"
>
{{ item.label }}
</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</template>
<script setup lang="ts">
const menus = [
{
label: '一级菜单',
command: 'level-1',
children: [
{
label: '二级菜单',
command: 'level-1-1',
children: [
{
label: '三级菜单',
command: 'level-1-1-1',
children: [{ label: '四级菜单', command: 'level-1-1-1-1' }],
},
],
},
{ label: '二级菜单(禁用)', disabled: true },
],
},
{
label: '一级菜单2',
command: 'level-2',
children: [
{ label: '二级菜单2-1', command: 'level-2-1' },
{ label: '二级菜单2-2', command: 'level-2-2' },
],
},
]
</script>
隐藏源代码
虚拟触发
可将菜单挂到任意参考元素上,实现触发器与内容分离。
Right click
vue
<template>
<u-card
class="content"
body-class="card-body"
@click="handleClick"
@contextmenu="handleContextmenu"
>
Right click
</u-card>
<u-dropdown
ref="dropdownRef"
:virtual-ref="triggerRef"
:show-arrow="false"
:popper-options="{
modifiers: [{ name: 'offset', options: { offset: [0, 0] } }],
}"
virtual-triggering
trigger="contextmenu"
placement="bottom-start"
>
<template #dropdown>
<u-dropdown-menu>
<u-dropdown-item :icon="Plus">Action 1</u-dropdown-item>
<u-dropdown-item :icon="CirclePlusFilled"> Action 2 </u-dropdown-item>
<u-dropdown-item :icon="CirclePlus">Action 3</u-dropdown-item>
<u-dropdown-item :icon="Check">Action 4</u-dropdown-item>
<u-dropdown-item :icon="CircleCheck">Action 5</u-dropdown-item>
</u-dropdown-menu>
</template>
</u-dropdown>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import {
Check,
CircleCheck,
CirclePlus,
CirclePlusFilled,
Plus,
} from '@uniboot/icons-vue'
import type { DropdownInstance } from 'uniboot-ui'
const dropdownRef = ref<DropdownInstance>()
const position = ref({
top: 0,
left: 0,
bottom: 0,
right: 0,
} as DOMRect)
const triggerRef = ref({
getBoundingClientRect: () => position.value,
})
const handleClick = () => {
dropdownRef.value?.handleClose()
}
const handleContextmenu = (event: MouseEvent) => {
const { clientX, clientY } = event
position.value = DOMRect.fromRect({
x: clientX,
y: clientY,
})
event.preventDefault()
dropdownRef.value?.handleOpen()
}
</script>
<style scoped>
.content {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
.content :deep(.card-body) {
flex-grow: 0;
}
</style>
隐藏源代码
下拉菜单 API
Dropdown 属性
| 名称 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| type | 菜单按钮类型,同 Button;仅在 split-button 为 true 时生效 | enum | '' |
| size | 菜单尺寸;对分割按钮同样生效 | enum | '' |
| button-props | 传递给按钮的属性,参见 按钮属性 | object | — |
| max-height | 菜单最大高度 | string / number | '' |
| split-button | 是否为分割按钮组 | boolean | false |
| disabled | 是否禁用 | boolean | false |
| placement | 菜单弹出方位 | enum | bottom |
| effect | 内置主题:dark / light,或自定义字符串 | enum / string | light |
| trigger | 触发方式 | enum / array | hover |
| trigger-keys | 键盘触发时响应的按键 | array | ['Enter', 'Space', 'ArrowDown', 'NumpadEnter'] |
| virtual-triggering | 是否启用虚拟触发 | boolean | — |
| virtual-ref | 虚拟触发时的参考元素 | HTMLElement | — |
| hide-on-click | 点击菜单项后是否隐藏菜单 | boolean | true |
| show-arrow | 是否显示箭头 | boolean | false |
| show-timeout | 悬停触发时延迟显示(毫秒) | number | 150 |
| hide-timeout | 悬停触发时延迟隐藏(毫秒) | number | 150 |
| role | 下拉菜单的 ARIA role,可按场景改为 navigation 等 | enum | menu |
| tabindex | 组件 tabindex,参见 MDN | number / string | 0 |
| popper-class | 下拉面板的自定义类名 | string / object | '' |
| popper-style | 下拉面板的自定义样式 | string / object | — |
| popper-options | popper.js 参数 | object | {modifiers: [{name: 'computeStyles',options: {gpuAcceleration: false}}]} |
| teleported | 是否将弹层挂载到 body | boolean | true |
| append-to | 下拉内容挂载到的目标元素 | CSSSelector / HTMLElement | — |
| persistent | 为 false 且未激活时是否销毁菜单 DOM | boolean | true |
Dropdown 插槽
| 名称 | 说明 | 子标签 |
|---|---|---|
| default | 触发器内容;须为合法 HTML 元素(如 <span>、<button>)或 el-/u- 组件,以便绑定监听 | — |
| dropdown | 下拉菜单内容,一般为 <u-dropdown-menu> | Dropdown-Menu |
Dropdown 事件
| 名称 | 说明 | 类型 |
|---|---|---|
| click | split-button 为 true 时,左侧按钮点击触发 | Function |
| command | 点击菜单项时触发,参数由该项 command 传入 | Function |
| visible-change | 下拉显示/隐藏时触发;显示为 true,隐藏为 false | Function |
Dropdown 暴露
| 方法 | 说明 | 类型 |
|---|---|---|
| handleOpen | 打开菜单 | Function |
| handleClose | 关闭菜单 | Function |
下拉菜单面板 API
Dropdown-Menu 插槽
| 名称 | 说明 | 子标签 |
|---|---|---|
| default | 菜单项集合 | Dropdown-Item |
下拉菜单项 API
Dropdown-Item 属性
| 名称 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| command | 点击时向 command 事件回传的指令值 | string / number / object | — |
| disabled | 是否禁用 | boolean | false |
| divided | 是否显示顶部分隔线 | boolean | false |
| icon | 自定义图标 | string / Component | — |
| children | 子菜单数据(递归) | array | — |
Dropdown-Item 插槽
| 名称 | 说明 |
|---|---|
| default | 菜单项文案 |
| icon | 自定义图标,优先级高于 icon 属性 |