菜单栏 (Menubar)
功能特性
- 可受控或非受控。
- 支持具有可配置阅读方向的子菜单。
- 支持项目、标签、项目组。
- 支持可勾选项目(单选或多选)。
- 可自定义侧边、对齐方式、偏移量、碰撞处理。
- 可选择渲染指向箭头。
- 焦点完全受管理。
- 完整的键盘导航。
- 支持类型前置搜索 (Typeahead)。
安装
从命令行安装该组件。
$ npm add reka-ui结构 (Anatomy)
导入所有部分并将它们组合在一起。
<script setup lang="ts">
import {
MenubarArrow,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarItemIndicator,
MenubarLabel,
MenubarMenu,
MenubarPortal,
MenubarRadioGroup,
MenubarRadioItem,
MenubarRoot,
MenubarSeparator,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from './'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger />
<MenubarPortal>
<MenubarContent>
<MenubarLabel />
<MenubarItem />
<MenubarGroup>
<MenubarItem />
</MenubarGroup>
<MenubarCheckboxItem>
<MenubarItemIndicator />
</MenubarCheckboxItem>
<MenubarRadioGroup>
<MenubarRadioItem>
<MenubarItemIndicator />
</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSub>
<MenubarSubTrigger />
<MenubarPortal>
<MenubarSubContent />
</MenubarPortal>
</MenubarSub>
<MenubarSeparator />
<MenubarArrow />
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>API 参考
Root (根组件)
包含菜单栏的所有部分。
| Prop | Default | Type |
|---|---|---|
defaultValue | stringThe value of the menu that should be open when initially rendered. Use when you do not need to control the value state. | |
dir | 'ltr' | 'rtl'The reading direction of the combobox when applicable. If omitted, inherits globally from | |
loop | false | booleanWhen |
modelValue | stringThe controlled value of the menu to open. Can be used as |
| Emit | Payload |
|---|---|
update:modelValue | [value: boolean]Event handler called when the value changes. |
| Slots (default) | Payload |
|---|---|
modelValue | stringCurrent input values |
Menu (菜单)
顶级菜单项,包含一个触发器与内容组合。
| Prop | Default | Type |
|---|---|---|
value | stringA unique value that associates the item with an active value when the navigation menu is controlled. This prop is managed automatically when uncontrolled. |
Trigger (触发器)
切换内容的按钮。默认情况下,MenubarContent 将根据触发器的位置进行定位。
| Prop | Default | Type |
|---|---|---|
as | 'button' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-highlighted] | 高亮时出现 |
[data-disabled] | 禁用时出现 |
Portal (传送门)
使用时,将内容部分传送到 body 中。
| Prop | Default | Type |
|---|---|---|
defer | booleanDefer the resolving of a Teleport target until other parts of the application have mounted (requires Vue 3.5.0+) | |
disabled | booleanDisable teleport and render the component inline | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. | |
to | string | HTMLElementVue native teleport component prop |
Content (内容)
菜单打开时弹出的组件。
| Prop | Default | Type |
|---|---|---|
align | 'start' | 'start' | 'center' | 'end'The preferred alignment against the trigger. May change when collisions occur. |
alignFlip | booleanFlip alignment when colliding with boundary.
May only occur when | |
alignOffset | numberAn offset in pixels from the | |
arrowPadding | numberThe padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. | |
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
avoidCollisions | booleanWhen | |
collisionBoundary | Element | (Element | null)[] | nullThe element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check. | |
collisionPadding | number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }. | |
disableUpdateOnLayoutShift | booleanWhether to disable the update position for the content when the layout shifted. | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. | |
hideWhenDetached | booleanWhether to hide the content when the trigger becomes fully occluded. | |
loop | booleanWhen | |
positionStrategy | 'fixed' | 'absolute'The type of CSS position property to use. | |
prioritizePosition | booleanForce content to be position within the viewport. Might overlap the reference element, which may not be desired. | |
reference | ReferenceElementThe custom element or virtual element that will be set as the reference to position the floating element. If provided, it will replace the default anchor element. | |
side | 'top' | 'right' | 'bottom' | 'left'The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled. | |
sideFlip | booleanFlip to the opposite side when colliding with boundary. | |
sideOffset | numberThe distance in pixels from the trigger. | |
sticky | 'partial' | 'always'The sticky behavior on the align axis. | |
updatePositionStrategy | 'always' | 'optimized'Strategy to update the position of the floating element on every animation frame. |
| Emit | Payload |
|---|---|
closeAutoFocus | [event: Event]Event handler called when auto-focusing on close. Can be prevented. |
escapeKeyDown | [event: KeyboardEvent]Event handler called when the escape key is down. Can be prevented. |
focusOutside | [event: FocusOutsideEvent]Event handler called when the focus moves outside of the |
interactOutside | [event: PointerDownOutsideEvent | FocusOutsideEvent]Event handler called when an interaction happens outside the |
pointerDownOutside | [event: PointerDownOutsideEvent]Event handler called when a |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-side] | "left" | "right" | "bottom" | "top" |
[data-align] | "start" | "end" | "center" |
| CSS Variable | Description |
|---|---|
--reka-menubar-content-transform-origin |
根据内容和箭头的位置/偏移计算出的 transform-origin
|
--reka-menubar-content-available-width |
触发器与边界边缘之间的剩余宽度
|
--reka-menubar-content-available-height |
触发器与边界边缘之间的剩余高度
|
--reka-menubar-trigger-width | 触发器的宽度 |
--reka-menubar-trigger-height | 触发器的高度 |
Arrow (箭头)
一个可选的箭头元素,与菜单栏菜单一起渲染。这可用于帮助在视觉上将触发器与 MenubarContent 联系起来。必须在 MenubarContent 内部渲染。
| Prop | Default | Type |
|---|---|---|
as | 'svg' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
height | 5 | numberThe height of the arrow in pixels. |
rounded | booleanWhen | |
width | 10 | numberThe width of the arrow in pixels. |
Item (项目)
包含菜单栏项目的组件。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the |
| Emit | Payload |
|---|---|
select | [event: Event]Event handler called when the user selects an item (via mouse or keyboard). |
| Data Attribute | Value |
|---|---|
[data-highlighted] | 高亮时出现 |
[data-disabled] | 禁用时出现 |
Group (组)
用于对多个 MenubarItem 进行分组。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Label (标签)
用于渲染标签。无法使用箭头键聚焦。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
CheckboxItem (复选框项目)
可以像复选框一样控制和渲染的项目。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen | |
modelValue | false | true | 'indeterminate'The controlled checked state of the item. Can be used as | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the |
| Emit | Payload |
|---|---|
select | [event: Event]Event handler called when the user selects an item (via mouse or keyboard). |
update:modelValue | [payload: boolean]Event handler called when the value changes. |
| Data Attribute | Value |
|---|---|
[data-state] | "checked" | "unchecked" |
[data-highlighted] | 高亮时出现 |
[data-disabled] | 禁用时出现 |
RadioGroup (单选按钮组)
用于对多个 MenubarRadioItem 进行分组。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
modelValue | stringThe value of the selected item in the group. |
| Emit | Payload |
|---|---|
update:modelValue | [payload: string]Event handler called when the value changes. |
RadioItem (单选按钮项目)
可以像单选按钮一样控制和渲染的项目。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the | |
value* | stringThe unique value of the item. |
| Emit | Payload |
|---|---|
select | [event: Event]Event handler called when the user selects an item (via mouse or keyboard). |
| Data Attribute | Value |
|---|---|
[data-state] | "checked" | "unchecked" |
[data-highlighted] | 高亮时出现 |
[data-disabled] | 禁用时出现 |
ItemIndicator (项目指示器)
当父级 MenubarCheckboxItem 或 MenubarRadioItem 被选中时渲染。您可以直接设置此元素的样式,或将其用作包装器来放入图标,或两者兼而有之。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |
| Data Attribute | Value |
|---|---|
[data-state] | "checked" | "unchecked" |
Separator (分隔符)
用于在菜单栏菜单中视觉上分隔项目。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Sub (子菜单)
包含子菜单的所有部分。
| Prop | Default | Type |
|---|---|---|
defaultOpen | booleanThe open state of the submenu when it is initially rendered. Use when you do not need to control its open state. | |
open | booleanThe controlled open state of the menu. Can be used as |
| Emit | Payload |
|---|---|
update:open | [payload: boolean]Event handler called when the open state of the submenu changes. |
| Slots (default) | Payload |
|---|---|
open | booleanCurrent open state |
SubTrigger (子菜单触发器)
打开子菜单的项目。必须在 MenubarSub 内部渲染。
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-highlighted] | 高亮时出现 |
[data-disabled] | 禁用时出现 |
SubContent (子菜单内容)
子菜单打开时弹出的组件。必须在 MenubarSub 内部渲染。
| Prop | Default | Type |
|---|---|---|
alignFlip | booleanFlip alignment when colliding with boundary.
May only occur when | |
alignOffset | numberAn offset in pixels from the | |
arrowPadding | numberThe padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. | |
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
avoidCollisions | booleanWhen | |
collisionBoundary | Element | (Element | null)[] | nullThe element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check. | |
collisionPadding | number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }. | |
disableUpdateOnLayoutShift | booleanWhether to disable the update position for the content when the layout shifted. | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. | |
hideWhenDetached | booleanWhether to hide the content when the trigger becomes fully occluded. | |
loop | booleanWhen | |
positionStrategy | 'fixed' | 'absolute'The type of CSS position property to use. | |
prioritizePosition | booleanForce content to be position within the viewport. Might overlap the reference element, which may not be desired. | |
reference | ReferenceElementThe custom element or virtual element that will be set as the reference to position the floating element. If provided, it will replace the default anchor element. | |
sideFlip | booleanFlip to the opposite side when colliding with boundary. | |
sideOffset | numberThe distance in pixels from the trigger. | |
sticky | 'partial' | 'always'The sticky behavior on the align axis. | |
updatePositionStrategy | 'always' | 'optimized'Strategy to update the position of the floating element on every animation frame. |
| Emit | Payload |
|---|---|
closeAutoFocus | [event: Event]Event handler called when auto-focusing on close. Can be prevented. |
entryFocus | [event: Event]Event handler called when container is being focused. Can be prevented. |
escapeKeyDown | [event: KeyboardEvent]Event handler called when the escape key is down. Can be prevented. |
focusOutside | [event: FocusOutsideEvent]Event handler called when the focus moves outside of the |
interactOutside | [event: PointerDownOutsideEvent | FocusOutsideEvent]Event handler called when an interaction happens outside the |
openAutoFocus | [event: Event]Event handler called when auto-focusing on open. Can be prevented. |
pointerDownOutside | [event: PointerDownOutsideEvent]Event handler called when a |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-side] | "left" | "right" | "bottom" | "top" |
[data-align] | "start" | "end" | "center" |
[data-orientation] | "vertical" | "horizontal" |
| CSS Variable | Description |
|---|---|
--reka-menubar-content-transform-origin |
根据内容和箭头的位置/偏移计算出的 transform-origin
|
--reka-menubar-content-available-width |
触发器与边界边缘之间的剩余宽度
|
--reka-menubar-content-available-height |
触发器与边界边缘之间的剩余高度
|
--reka-menubar-trigger-width | 触发器的宽度 |
--reka-menubar-trigger-height | 触发器的高度 |
示例
带子菜单
您可以通过结合使用 MenubarSub 及其部件来创建子菜单。
<script setup lang="ts">
import {
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarSeparator,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>子菜单 →</MenubarSubTrigger>
<MenubarPortal>
<MenubarSubContent>
<MenubarItem>子菜单项</MenubarItem>
<MenubarItem>子菜单项</MenubarItem>
<MenubarArrow />
</MenubarSubContent>
</MenubarPortal>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>…</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>带禁用项
您可以通过 data-disabled 属性为禁用的项目添加特殊样式。
<script setup lang="ts">
import { MenubarContent, MenubarItem, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem
class="MenubarItem"
disabled
>
…
</MenubarItem>
<MenubarItem class="MenubarItem">
…
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarItem[data-disabled] {
color: gainsboro;
}带分隔符
使用 Separator 部件在项目之间添加分隔符。
<script setup lang="ts">
import {
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarSeparator,
MenubarTrigger,
} from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarItem>…</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>带标签
使用 Label 部件帮助标记一个区域。
<script setup lang="ts">
import {
MenubarContent,
MenubarItem,
MenubarLabel,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarTrigger,
} from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarLabel>标签</MenubarLabel>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>带复选框项目
使用 CheckboxItem 部件添加一个可以勾选的项目。
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import {
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarItemIndicator,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarSeparator,
MenubarTrigger,
} from 'reka-ui'
const checked = ref(true)
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarCheckboxItem v-model="checked">
<MenubarItemIndicator>
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
复选框项目
</MenubarCheckboxItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>带单选按钮项目
使用 RadioGroup 和 RadioItem 部件添加可以在其他项目中单选的项目。
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import {
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarItemIndicator,
MenubarMenu,
MenubarPortal,
MenubarRadioGroup,
MenubarRadioItem,
MenubarRoot,
MenubarSeparator,
MenubarTrigger,
} from 'reka-ui'
const color = ref('blue')
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarRadioGroup v-model="color">
<MenubarRadioItem value="red">
<MenubarItemIndicator>
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
红色
</MenubarRadioItem>
<MenubarRadioItem value="blue">
<MenubarItemIndicator>
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
蓝色
</MenubarRadioItem>
</MenubarRadioGroup>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>带复杂项目
您可以在 Item 部件中添加额外的装饰性元素,例如图像。
<script setup lang="ts">
import { MenubarContent, MenubarItem, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>
<img src="…">
Adolfo Hess
</MenubarItem>
<MenubarItem>
<img src="…">
Miyah Myles
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>限制内容/子内容的大小
您可能希望限制内容(或子内容)的宽度以匹配触发器(或子触发器)的宽度。您可能还希望限制其高度不超过视口。
我们公开了几个 CSS 自定义属性,例如 --reka-menubar-trigger-width 和 --reka-menubar-content-available-height 来支持这一点。使用它们来限制内容的尺寸。
<script setup lang="ts">
import { MenubarContent, MenubarItem, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger> 触发器 </MenubarTrigger>
<MenubarPortal>
<MenubarContent
class="MenubarContent"
:side-offset="5"
:align-offset="-3"
>
<MenubarItem> 新建标签页 </MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarContent {
width: var(--reka-menubar-trigger-width);
max-height: var(--reka-menubar-content-available-height);
}感知原点的动画
我们公开了一个 CSS 自定义属性 --reka-menubar-content-transform-origin。使用它可以根据 side、sideOffset、align、alignOffset 以及任何碰撞情况,从计算出的原点对内容进行动画处理。
<script setup lang="ts">
import { MenubarContent, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent class="MenubarContent">
…
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarContent {
transform-origin: var(--reka-menubar-content-transform-origin);
animation: scaleIn 0.5s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}感知碰撞的动画
我们公开了 data-side 和 data-align 属性。它们的值将在运行时改变以反映碰撞情况。使用它们来创建碰撞和方向感知的动画。
<script setup lang="ts">
import { MenubarContent, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'reka-ui'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent class="MenubarContent">
…
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarContent {
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.MenubarContent[data-side="top"] {
animation-name: slideUp;
}
.MenubarContent[data-side="bottom"] {
animation-name: slideDown;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}可访问性
遵循 菜单按钮 WAI-ARIA 设计模式 并使用 roving tabindex 来管理菜单项之间的焦点移动。
键盘交互
| Key | Description |
|---|---|
空格键 (Space) |
当焦点在 MenubarTrigger 上时,打开菜单栏并聚焦第一个项目。
当焦点在某个项目上时,激活聚焦的项目。 |
回车键 (Enter) |
当焦点在 MenubarTrigger 上时,打开关联的菜单。
当焦点在某个项目上时,激活聚焦的项目。 |
向下箭头 (ArrowDown) |
当焦点在 MenubarTrigger 上时,打开关联的菜单。
当焦点在某个项目上时,将焦点移动到下一个项目。 |
向上箭头 (ArrowUp) | 当焦点在某个项目上时,将焦点移动到上一个项目。 |
向右箭头 (ArrowRight)向左箭头 (ArrowLeft) |
当焦点在 MenubarTrigger 上时,将焦点移动到下一个或上一个项目。当焦点在 MenubarSubTrigger 上时,根据阅读方向打开或关闭子菜单。当焦点在 MenubarContent 内时,打开菜单栏中的下一个菜单。
|
Esc 键 |
关闭当前打开的菜单并将焦点移动到其 MenubarTrigger。
|
