Skip to content

ContextMenu 右键菜单 ​

在一块区域上右键(触屏长按),在指针处弹出一列命令:画布上的复制 / 粘贴 / 排列、表格行的编辑 / 删除、文件列表的重命名。 菜单内容与 Menu 下拉菜单 完全相同,行为(键盘、子菜单、选中即关)也一样,区别只在怎么打开、弹在哪里。 需要一个看得见的按钮来打开时用 Menu —— 右键菜单不可发现,里面的命令最好在别处(工具栏、行尾的「更多」按钮)也能找到。

基础用法

trigger 插槽里的元素就是右键区域:在上面右键(触屏长按)弹出菜单,面板左上角贴着指针。菜单内容与 pt-menu 相同。

<pt-context-menu aria-label="画布">
  <div slot="trigger" style="display: flex; align-items: center; justify-content: center; width: 320px; height: 160px; border: 1px dashed var(--pt-border-strong); border-radius: 8px; color: var(--pt-text-weak); user-select: none">在这里右键</div>
  <pt-menu-item value="back">
    返回
    <span slot="end">⌘[</span>
  </pt-menu-item>
  <pt-menu-item value="forward" disabled>
    前进
    <span slot="end">⌘]</span>
  </pt-menu-item>
  <pt-menu-item value="reload">
    重新加载
    <span slot="end">⌘R</span>
  </pt-menu-item>
  <pt-separator></pt-separator>
  <pt-menu-sub>
    <span slot="trigger">更多工具</span>
    <pt-menu-item value="save">页面另存为…</pt-menu-item>
    <pt-menu-item value="devtools">开发者工具</pt-menu-item>
  </pt-menu-sub>
  <pt-separator></pt-separator>
  <pt-menu-item type="checkbox" checked>显示书签栏</pt-menu-item>
  <pt-menu-group type="radio" value="pedro" label="成员">
    <pt-menu-item type="radio" value="pedro">Pedro</pt-menu-item>
    <pt-menu-item type="radio" value="colm">Colm</pt-menu-item>
  </pt-menu-group>
</pt-context-menu>

组成 ​

元素作用
pt-context-menu根:trigger 插槽放右键区域,默认插槽放菜单内容
菜单内容与 Menu 相同:pt-menu-item、pt-menu-group、pt-menu-label、pt-menu-sub、pt-separator,API 见 Menu

宿主 display: contents,自己不产生盒子:区域直接参与外面的布局(放在 flex / grid 里时区域本身就是那个格子), 尺寸与样式写在 trigger 元素上。

打开 ​

  • 右键(macOS 上 Ctrl+点击同样):拦下浏览器自带的右键菜单,面板左上角贴着指针弹出、往右下展开; 贴近视口下边缘时翻到指针上方,贴近右边缘时往左收进视口。
  • 菜单开着时在区域别处再右键:先关闭(ptClose,reason: 'outside')再在新位置打开(ptOpen)。
  • 触屏长按约 700ms 打开;按住期间手指移动超过约 10px(在滚动)取消。长按打开后松手产生的 click 会被吞掉, 区域里的按钮、链接不会因此被激活;区域上也关掉了 iOS 长按弹出的系统菜单。
  • 键盘:区域里的元素聚焦时按 Shift+F10 或 ContextMenu 键,从区域中心打开并聚焦第一项。 组件不给区域加 tabindex:区域要不要能聚焦由你决定(区域里通常本来就有可聚焦的元素;整块区域要能聚焦就自己写 tabindex="0")。
  • 外部把 open 写成 true 时从区域中心打开。
  • disabled 时以上都不生效,区域上照常出现浏览器自带的右键菜单。

关闭与焦点 ​

与 Menu 相同:选中一项 select、按 Esc escape、在菜单外(包括区域里)按下指针 outside、 按 Tab tab,关闭并发 ptClose(detail.reason 与 Menu 同一组取值,右键菜单不会出现 trigger)。 关闭时焦点若在菜单里,回到打开前聚焦的元素;点外面关闭时不抢焦点。外部把 open 写成 false 只关闭,不发 ptClose。

选中 ​

ptSelect 由菜单项发出并冒泡;pt-context-menu 声明了同名事件,所以 React / Vue / Angular 里都可以直接写在菜单上: <PtContextMenu onPtSelect={…}>、<PtContextMenu @pt-select="…">、<pt-context-menu (ptSelect)="…">。 event.detail 是菜单项的 value,event.target 是那个菜单项;在菜单上 preventDefault() 同样让菜单保持打开。

区域里若还放了一个 pt-menu(例如卡片右上角的「更多」按钮),它的菜单项选中时也会冒泡经过 pt-context-menu, 按 event.target.closest('pt-context-menu, pt-menu') 区分来源。

类型提示:生成的事件类型把 event.target 标成 pt-context-menu(Stencil 按声明事件的元素定 target 类型),运行时它是菜单项。 要读菜单项的属性时写 event.target as HTMLPtMenuItemElement;只按 detail 分派命令则不受影响。

与 Menu 的视觉差异 ​

照源组件 ContextMenu:

项MenuContextMenu
分隔线bg-secondary(更淡)border-default
快捷键提示继承文字色、60% 不透明度text-weak

源组件里标题行与子菜单触发行聚焦时的 text-strong,Kit 的菜单行本来就是 text-strong,两者一致。 窄屏下同样不切底部抽屉。

API ​

属性

属性Attribute类型默认值说明
ariaLabelTextaria-labelstring | undefined—菜单面板(role="menu")的无障碍名称:原生 HTML 里写 aria-label, React / Vue / Angular 包装层里属性名是 ariaLabelText。
disableddisabledbooleanfalse禁用:右键、长按、Shift+F10 都不再打开菜单(区域上照常出现浏览器自带的右键菜单)。 长按计时中变为禁用:计时作废,松手的 click 照常。已经开着的菜单不受影响(与 pt-menu-sub 一致),照常关闭
openopenbooleanfalse是否展开。用户交互时组件自己改写;外部直接赋值立即生效、不发 ptClose。 外部打开(没有指针坐标)时从区域中心弹出

事件

事件detail 类型说明
ptClose{ reason: PtMenuCloseReason; }用户交互关闭后触发,detail 说明是怎么关的(与 pt-menu 同一组 reason)。外部把 open 写成 false **不发** **不冒泡**:弹层常互相嵌套(弹窗里的菜单、气泡卡片里的下拉),冒泡的话外层上的监听会收到内层的开关。
ptOpenvoid面板渲染出来之后发(交互或属性打开都发) **不冒泡**:弹层常互相嵌套(弹窗里的菜单、气泡卡片里的下拉),冒泡的话外层上的监听会收到内层的开关。
ptSelectstring | undefined某个菜单项被选中,detail 为它的 `value`,`event.target` 是那个菜单项。 这是 `pt-menu-item` 发出、冒泡上来的事件,本元素**自己不发**;声明在这里只为让 React / Vue / Angular 包装层生成绑定(`onPtSelect` / `@pt-select` / `(ptSelect)`),可以在菜单上统一监听,不必写在每一项上。 在这里 `preventDefault()` 同样阻止菜单关闭。 注意区域(`trigger` 插槽)里若另有 `pt-menu`,它的菜单项选中时也会冒泡到这里,按 `event.target` 区分。 静态类型的限制:Stencil 生成的 `PtContextMenuCustomEvent` 把 `target` 标成声明事件的元素(本元素),运行时却是菜单项; 要读菜单项时写 `event.target as HTMLPtMenuItemElement`。只按 `detail` 分派命令则无需关心。

插槽

名称说明
(默认)菜单内容:`pt-menu-item`、`pt-menu-group`、`pt-menu-label`、`pt-menu-sub`、`pt-separator`
trigger右键区域(右键、长按、Shift+F10 在这里打开菜单)

可定制的内部元素(::part())

part说明
panel菜单面板(role="menu")

Apache-2.0 协议开源