QMenu 组件是一个方便展示菜单的方式。它可以很好地与 QList 作为下拉内容搭配使用,但不仅限于此。
用法
QMenu 的设计理念是将其作为触发器 DOM 元素/组件的直接子元素放置。不用担心 QMenu 内容会从容器继承 CSS,因为 QMenu 会通过 Quasar Portal 作为 <body> 的直接子元素注入。
如果您希望菜单可以自动关闭,不要忘记给可点击的菜单项加上 v-close-popup 指令。另外,也可以使用 QMenu 的 auto-close 属性,或者自行通过 v-model 来处理关闭操作。
基础
如果您想要有条件地激活或停用 QMenu,请使用 v-if 而不是 v-show。
悬停打开 v2.26+
使用 hover 属性后,当鼠标悬停在目标元素上时菜单会自动打开,当指针离开目标和菜单后菜单关闭。hover-hide-delay 属性控制指针在两者之间移动(或返回)时菜单延迟关闭的宽限期,hover-delay 则延迟打开。
点击/轻触和键盘交互仍然照常切换菜单,因此触屏设备(没有悬停事件)会自然降级为点击交互;这也意味着当菜单因悬停而打开时,点击目标(或用 Enter 激活目标)会关闭它。悬停打开的菜单不会将键盘焦点移入菜单内部。子菜单同样适用:从父菜单悬停到由它打开的子菜单时,整个菜单链保持打开。
hover 和 context-menu 属性互斥;同时设置时,context-menu 优先生效,hover 无效。此外,悬停触发的打开会忽略 touch-position,该属性仅对点击/轻触打开生效。
子菜单
尺寸和样式
上下文菜单
您还可以将 QMenu 作为上下文菜单。右键点击父目标即可触发,触屏设备上长按同样适用。上下文菜单仅通过这些交互方式打开,因此 hover 属性对其无效。
持久化
如果您希望在应用路由变化、按下 ESCAPE 键或点击/触摸 QMenu 外部时不要关闭菜单,那么请使用 persistent 属性:
过渡
在下面的示例中,展示了一些过渡效果。有关可用过渡的完整列表,请转到 过渡效果 页面。
可复用
下面的示例展示了如何创建一个可在不同目标容器中复用的菜单。
定位
QMenu 的位置可以自定义。它会考虑 anchor 和 self 这两个可选属性。QMenu 弹出框的最终位置是计算得出的,以便使其显示在可用的屏幕空间上,并在必要时切换到右侧和/或顶部。
对于水平定位,您可以使用 start 和 end 来自动适应 RTL 或非 RTL。start 和 end 在非 RTL 中表示"左",在 RTL 中表示"右"。
offset 属性是相对于锚点元素的边界框来应用的,应用之后最终位置才会被限制在可用的屏幕空间内。因此,如果偏移量过大,或者 QMenu 锚定在一个全宽/紧贴屏幕边缘的元素上,弹出层可能会被推到视口边缘而被强制裁剪,此时 offset 看起来就像没有生效(被裁剪后的位置与 offset 值无关了)。如果你发现 offset 在某个轴向上似乎被忽略了,请确保所选的 anchor/self 让弹出层有足够的自由空间来扩展——例如,将 QMenu 挂载到一个 inline / inline-block 触发器上,而不是一个全宽的块级元素上。
<q-menu hover anchor="bottom left" self="top left">
<q-item clickable>
<q-item-section>New tab</q-item-section>
</q-item>
<q-item clickable>
<q-item-section>New incognito tab</q-item-section>
</q-item>
</q-menu>无障碍访问 v2.25+
语义
QMenu 渲染为一个普通的定位容器,刻意不声明任何 ARIA role:它可以承载任何类型的内容,而 WAI-ARIA menu role 只允许菜单项作为子元素——表单、日期选择器或列表放在其下都会导致标记无效。
所以当弹出内容确实是一个菜单——一组命令时——请通过在包裹的 QList 上设置 role="menu" 来声明。其中的 QItem 会自动适配:可操作的条目(clickable 或链接条目,包括禁用的)将自身暴露为 menuitem,其他内容(节标题等)保持中性,QSeparator 已经自带 separator 语义。单个条目可以覆盖其派生的 role——例如用 role="menuitemcheckbox" 或 role="menuitemradio" 用于切换条目,此时管理 aria-checked 就是你的责任了。上方的"基础"示例展示了声明方式。
如果你将 role 附加到 QMenu 容器本身(它会透传你传入的任何 role),请确保其全部内容都满足该 role 的要求。
锚点语义
锚点是你自己的标记,但它是打开弹出层的控件,所以 QMenu 会从外部维护触发器的 ARIA:aria-expanded 跟随打开状态,QMenu 容器上声明的 role 会镜像到锚点上作为 aria-haspopup(该属性命名弹出层的 role,所以只有 menu、listbox、tree、grid 和 dialog 可以被镜像)。因此包裹 QMenu 的 <q-btn> 会被播报为一个折叠或展开的触发器,无需额外工作。
这要求锚点是 ARIA 允许设置该状态的元素——<button>、带 href 的链接,或声明了小部件 role(如 role="button")的任何元素。普通 <div> 计算为通用 role,aria-expanded 在其上是无效的,所以 QMenu 不会触碰它:在将这样的锚点用作触发器之前,请给它一个合适的 role(以及键盘激活路径)。另外两种情况也被刻意不处理——context-menu(上下文菜单)弹出层(通过右键或长按打开而非激活),以及你自行在锚点上设置的 aria-expanded/aria-haspopup(QMenu 永远不会覆盖它们)。
请注意,当 role 放在弹出层内部的 QList 上——即上文推荐的形式——QMenu 看不到它,所以请自行在锚点上添加 aria-haspopup="menu":
<q-btn label="操作" aria-haspopup="menu">
<q-menu>
<q-list role="menu">
<!-- ... -->
</q-list>
</q-menu>
</q-btn>键盘导航
由于菜单渲染在页面末尾附近,如果 Tab 越过其最后一个可聚焦元素(或 Shift + Tab 越过第一个),键盘焦点会脱离页面。遵循 WAI-ARIA APG,菜单会关闭并将焦点从锚点继续,就像 Escape 关闭菜单并将焦点返回锚点一样。菜单 内部 多个可聚焦元素之间的 Tab 导航照常工作,persistent(持久性)菜单也会取消此关闭行为。
注意可聚焦的菜单项是普通的 Tab 焦点——QMenu 目前还不提供 APG 菜单模式 中为 role="menu" 内容描述的方向键导航。