反馈 · 10 / 21
Menu st-menu
下拉菜单:trigger 插槽放触发器,菜单项写在 light DOM 的 st-menu-item 里。面板 fixed 定位自动翻转,点外部 / Escape / 选中后关闭;支持分隔线、禁用项、prefix / suffix、多级子菜单、右键 openAt 与命令式 contextMenu。
基础:trigger 与菜单项
触发器必须带 slot="trigger";st-menu-item 直接写在 st-menu 内。菜单项之间放原生 hr 就是分隔线,disabled 项降到 0.38 透明度并阻断点击。
st-menu / st-menu-item示例代码
<st-menu>
<st-button slot="trigger" variant="outlined">操作菜单 ▾</st-button>
<st-menu-item on:click="pick('编辑')">
<span slot="prefix">✏️</span>编辑<span slot="suffix">⌘E</span>
</st-menu-item>
<st-menu-item disabled>删除(禁用)</st-menu-item>
<hr />
<st-menu-item>关于</st-menu-item>
</st-menu>
align 与 sync:open
align 控制面板与触发器的水平对齐,默认 right、可设 left。open 是运行时状态:用 sync:open 绑定后,选中菜单项、点击外部或 Escape 导致的关闭都会回写到页面数据。
align / sync:open示例代码(开合状态双向绑定)
<st-menu sync:open="menuOpen">
<st-button slot="trigger">右对齐菜单 ▾</st-button>
<st-menu-item>选项一</st-menu-item>
</st-menu>
<st-menu align="left">
<st-button slot="trigger">左对齐菜单 ▾</st-button>
<st-menu-item>选项 A</st-menu-item>
</st-menu>
prefix、suffix 与多级子菜单
子菜单写在某个 st-menu-item 的 sub-menu 插槽里:该 item 仍是普通一项,自动显示 ▸ 箭头,hover 展开(触屏点击开合)。选中任意层级后整条链关闭,Escape 只关最内层。
sub-menu示例代码(子菜单)
<st-menu>
<st-button slot="trigger">导出菜单 ▾</st-button>
<st-menu-item>
导出为
<st-menu slot="sub-menu">
<st-menu-item>PDF</st-menu-item>
<st-menu-item>Markdown</st-menu-item>
<st-menu-item>PNG 图片</st-menu-item>
</st-menu>
</st-menu-item>
</st-menu>
右键定位:openAt(x, y)
不需要 trigger:在 contextmenu 事件里阻止浏览器默认菜单,再调用 openAt(clientX, clientY)。面板左上角对齐光标,右侧 / 下方空间不足时自动翻转到左 / 上,并夹紧在视口内。
openAt示例代码
<div on:contextmenu="onCtx">右键区域</div>
<st-menu id="ctxMenu">
<st-menu-item>剪切</st-menu-item>
<st-menu-item>复制</st-menu-item>
</st-menu>
<script>
export default async () => ({
proto: {
onCtx(e) {
e.preventDefault();
this.shadow.$("#ctxMenu").openAt(e.clientX, e.clientY);
},
},
});
</script>
命令式右键菜单 contextMenu
动态菜单用命令式工具更省事:传事件(自动取坐标)或 {x, y},items 数组支持 separator 与 children 子菜单,await 得到点击的叶子项 id;点空白或 Escape 返回 null。工具自动挂 body,用完即毁。
window.__site.contextMenu示例代码
import contextMenu from "/packages/menu/context-menu.js";
const id = await contextMenu(e, [
{ id: "cut", label: "剪切", prefix: "✂️" },
{ id: "copy", label: "复制", suffix: "⌘C" },
{ separator: true },
{
id: "sort",
label: "排序",
children: [
{ id: "sort-name", label: "按名称" },
{ id: "sort-size", label: "按大小" },
],
},
{ id: "del", label: "删除", disabled: true },
]);
// id → "cut" / "sort-name";取消 → null
键盘、外部点击与对话框内使用
触发器是原生按钮:Tab 聚焦、Enter / Space 打开;面板内菜单项可 Tab 到达并用 Enter / Space 激活。点击面板外部或按 Escape 关闭。菜单面板会换算 transform 祖先的定位原点,所以放进 st-dialog 也不会漂移。
menu inside dialog示例代码(对话框内的菜单)
<st-dialog sync:open="dlgMenu" auto-close>
<h2 slot="headline">选择操作</h2>
<st-menu>
<st-button slot="trigger">操作 ▾</st-button>
<st-menu-item on:click="pick('重命名')">重命名</st-menu-item>
<st-menu-item on:click="pick('移动')">移动</st-menu-item>
</st-menu>
</st-dialog>
属性
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
align | "left" | "right" | "right" | 面板与触发器的水平对齐 |
open | 运行时状态(ofa data) | false | 开合状态;页面里用 sync:open="key" 绑定 |
disabled | boolean(st-menu-item) | 无 | 禁用菜单项:0.38 透明度、阻断点击 |
插槽 / 事件 / 注意
- 插槽:
trigger放触发器;st-menu-item 支持prefix/ 默认文字 /suffix/sub-menu;分隔线用原生<hr>。 - 事件:
open/close(bubbles + composed);菜单项 click 正常冒泡,面板随后自动关闭。 - 关闭:选中任意层级、点击面板外部、Escape;多级菜单的 Escape 从最内层逐次向外。
- 命令式:
contextMenu(e, items)返回叶子项 id;contextMenu.longPress(el, items, onSelect)支持触屏长按。 - 面板默认
min-width: 6em、padding / 圆角0.286em / 0.857em、max-height: 80vh(内部滚动),宽度由内容决定。