Skip to content

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" />
属性默认说明
closeOnScrolltrue页面滚动时关闭
closeOnSelecttrue选中后关闭

滚动时关闭是必需的

菜单的位置是打开那一刻按光标算出来的。页面滚动后这个坐标就失效了, 菜单会悬在半空、指着一个毫不相关的位置。

不关的话用户会看到菜单「飘」在那里——比直接关掉更让人困惑。

在列表里区分上下文

右键菜单常见于列表——不同行的菜单内容可能不同

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

名称类型默认值说明
optionsSrContextMenuOption[][]菜单项
disabledbooleanfalse是否禁用
closeOnScrollbooleantrue页面滚动时关闭
closeOnSelectbooleantrue选中后关闭

插槽

名称说明
default右键响应区域

事件

事件参数说明
select(option)选中某一项
visible-changeboolean显隐变化

无障碍

右键菜单无法只靠键盘操作

这是这类组件的固有限制——「右键」本身没有键盘等价物

实际做法有两条:

  1. 同时提供一个「更多」按钮SrDropdown), 用键盘能打开同一个菜单。这是最稳的方案;
  2. 或在列表项上支持 Shift + F10 / 菜单键——但用户是否知道这个快捷键 是个问题。
  • 菜单容器带 role="menu",每项 role="menuitem"
  • 打开时焦点移入菜单,方向键可导航
  • Esc 关闭后焦点归还给右键点击的那个元素

自用组件库 · 源码分发 · 不发布 npm