ContextMenu 右键菜单
按光标位置弹出的菜单。
基础用法
在下面的虚线框内点右键:
在这里点右键
最近选择:(尚未使用)
vue
<script setup>
const options = [
{ value: 'open', label: '打开' },
{ value: 'rename', label: '重命名', shortcut: 'F2', divided: true },
{ value: 'remove', label: '移出列表', danger: true }
]
</script>
<template>
<SrContextMenu :options="options" @select="onSelect">
<div class="right-click-zone">在这里点右键</div>
</SrContextMenu>
</template>按光标定位
与 Dropdown 不同,右键菜单的位置由光标决定,而不是由触发器元素决定。
在这个区域的不同位置点右键,菜单会在光标处弹出
vue
<SrContextMenu :options="options">…</SrContextMenu>视口边缘校正
光标靠近窗口右下角时,菜单会向左、向上翻转—— 而不是被裁掉一半。
这是右键菜单的必备能力:用户可能在任何位置右键, 固定方向一定会出界。
为什么要先量再显示
菜单的尺寸在渲染前是未知的(选项数量与文本长度都不固定)。 组件的做法是先渲染但设为不可见、量出尺寸、计算位置、再显示。
直接用 CSS 的 right: 0 之类是解决不了的—— 「离右边多远」取决于菜单自身宽度,而那是个变量。
选项字段
与 Dropdown 的选项结构一致:
ts
interface SrContextMenuOption {
value: string | number
label: string
disabled?: boolean
danger?: boolean
divided?: boolean
shortcut?: string
children?: SrContextMenuOption[]
}shortcut 会显示在右侧——它只是提示,不会真的绑定快捷键。 真正注册快捷键需要在应用层处理(useEventListener + keydown), 因为组件不知道你的焦点在哪里。
关闭时机
打开菜单后滚动页面,菜单会自动关闭
vue
<SrContextMenu :close-on-scroll="true" />
<SrContextMenu :close-on-select="true" />| 属性 | 默认 | 说明 |
|---|---|---|
closeOnScroll | true | 页面滚动时关闭 |
closeOnSelect | true | 选中后关闭 |
滚动时关闭是必需的
菜单的位置是打开那一刻按光标算出来的。页面滚动后这个坐标就失效了, 菜单会悬在半空、指着一个毫不相关的位置。
不关的话用户会看到菜单「飘」在那里——比直接关掉更让人困惑。
在列表里区分上下文
右键菜单常见于列表——不同行的菜单内容可能不同。
vue
<script setup>
const currentRow = ref(null)
function onContextMenu(row) {
currentRow.value = row
}
const options = computed(() => [
{ value: 'open', label: '打开' },
// 按当前行决定是否显示某些项
...(currentRow.value?.editable
? [{ value: 'edit', label: '编辑' }]
: []),
{ value: 'remove', label: '移除', danger: true, divided: true }
])
</script>
<template>
<SrContextMenu :options="options" @select="onSelect">
<div v-for="row in rows" :key="row.id" @contextmenu="onContextMenu(row)">
{{ row.name }}
</div>
</SrContextMenu>
</template>Props
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
options | SrContextMenuOption[] | [] | 菜单项 |
disabled | boolean | false | 是否禁用 |
closeOnScroll | boolean | true | 页面滚动时关闭 |
closeOnSelect | boolean | true | 选中后关闭 |
插槽
| 名称 | 说明 |
|---|---|
default | 右键响应区域 |
事件
| 事件 | 参数 | 说明 |
|---|---|---|
select | (option) | 选中某一项 |
visible-change | boolean | 显隐变化 |
无障碍
右键菜单无法只靠键盘操作
这是这类组件的固有限制——「右键」本身没有键盘等价物。
实际做法有两条:
- 同时提供一个「更多」按钮(
SrDropdown), 用键盘能打开同一个菜单。这是最稳的方案; - 或在列表项上支持
Shift + F10/ 菜单键——但用户是否知道这个快捷键 是个问题。
- 菜单容器带
role="menu",每项role="menuitem" - 打开时焦点移入菜单,方向键可导航
Esc关闭后焦点归还给右键点击的那个元素