@ data- slot/ 导航菜单
香草JavaScript的无头导航菜单(mega菜单)组件. 无障碍而无作相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相.
安装
npm install @data-slot/navigation-menu
快速启动
<nav data-slot="navigation-menu">
<ul data-slot="navigation-menu-list">
<li data-slot="navigation-menu-item" data-value="products">
<button data-slot="navigation-menu-trigger">Products</button>
<div data-slot="navigation-menu-content">
<a href="/product-a">Product A</a>
<a href="/product-b">Product B</a>
</div>
</li>
<li data-slot="navigation-menu-item" data-value="company">
<button data-slot="navigation-menu-trigger">Company</button>
<div data-slot="navigation-menu-content">
<a href="/about">About</a>
<a href="/careers">Careers</a>
</div>
</li>
<li data-slot="navigation-menu-indicator" role="presentation" aria-hidden="true"></li>
</ul>
<div data-slot="navigation-menu-portal">
<div data-slot="navigation-menu-positioner">
<div data-slot="navigation-menu-popup">
<div data-slot="navigation-menu-viewport"></div>
</div>
</div>
</div>
</nav>
<script type="module">
import { create } from "@data-slot/navigation-menu";
const controllers = create();
</script>
只有作者的最小标记 navigation-menu-viewport 还行 运行时间
在菜单打开时生成弹出堆栈,并在关闭时恢复原来的DOM.
API 密码
初始化
create(scope?)
自动发现并绑定范围中的所有导航菜单例(默认为 document) (中文(简体) ).
import { create } from "@data-slot/navigation-menu";
const controllers = create(); // Returns NavigationMenuController[]
createNavigationMenu(root, options?)
为特定元素创建控制器.
import { createNavigationMenu } from "@data-slot/navigation-menu";
const menu = createNavigationMenu(element, {
delayOpen: 0,
delayClose: 0,
onValueChange: (value) => console.log(value),
});
槽数
运行时间槽
navigation-menu- 管理活动面板和打开状态的根导航元素.navigation-menu-list- 包含导航项目的必要顶级列表;用于发现顶级悬浮和聚焦目标.navigation-menu-item- 航行入境集装箱;至少需要一件物品。 使用data-value以识别带有内容面板的条目.navigation-menu-trigger- 打开其相关内容面板的项目中的按钮.navigation-menu-content- 项目内的内容面板,当项目活动时显示.navigation-menu-indicator- 可选动画亮点,紧随顶级悬浮/聚焦目标,在面板打开时仍固定在主动触发器上.navigation-menu-portal- 门户包装器移到document.body当菜单打开时.navigation-menu-positioner- 弹出式定位包,接收已解析的侧/对齐属性和大小变量.navigation-menu-popup- 动画弹出外壳在取景口周围.navigation-menu-viewport- 可选剪辑取景口,该取景口设有活动内容面板.navigation-menu-viewport-positioner- 折旧的别名navigation-menu-positioner。 。 。 .
生成槽
navigation-menu-bridge- 运行时创建的悬浮安全屏蔽,既能保持菜单的开放,又能跨越缺口到其内容.navigation-menu-safe-triangle- 运行时创建调试多边形,在调试启用时可视化悬浮安全走廊.
标记
<nav data-slot="navigation-menu">
<ul data-slot="navigation-menu-list">
<li data-slot="navigation-menu-item" data-value="unique-id">
<button data-slot="navigation-menu-trigger">Label</button>
<div data-slot="navigation-menu-content">
<!-- Links, content -->
</div>
</li>
<!-- Optional hover indicator -->
<li data-slot="navigation-menu-indicator" role="presentation" aria-hidden="true"></li>
</ul>
<div data-slot="navigation-menu-portal">
<div data-slot="navigation-menu-positioner">
<div data-slot="navigation-menu-popup">
<div data-slot="navigation-menu-viewport"></div>
</div>
</div>
</div>
</nav>
如果你只写 navigation-menu-viewport,运行时间合成缺失
navigation-menu-portal, (中文(简体) ), navigation-menu-positioner,以及 navigation-menu-popup
菜单打开时的包装符 .
数据属性
也可以通过根元素上的数据属性来设定选项. 联合来文的选择优先.
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
data-delay-open | 编号 | 0 | 悬浮开始前的延迟( 毫秒) |
data-delay-close | 编号 | 0 | 关闭鼠标休假前的延迟( 毫秒) |
data-open-on-focus | 布尔 | false | 聚焦触发是否打开其内容 |
data-mount-strategy | "lazy" | "eager" | "lazy" | 切除不活动面板或保持其连接和隐藏 |
data-side | 字符串 | "bottom" | 侧: "top", (中文(简体) ), "right", (中文(简体) ), "bottom", (中文(简体) ), "left" |
data-align | 字符串 | "start" | 视图端口对齐 : "start", (中文(简体) ), "center",或 "end" |
data-side-offset | 编号 | 0 | 从触发到取景口的距离( px) |
data-align-offset | 编号 | 0 | 交叉轴对齐相抵 (px) |
data-position-method | 字符串 | "absolute" | 定位战略: "absolute" 或者说 "fixed" |
data-safe-triangle | 布尔 | false | 启用悬空安全三角切换保护 |
data-debug-safe-triangle | 布尔 | false | 显示红色悬浮安全三角调试覆盖 |
布尔属性: 存在或 "true" 没错, "false" =虚假,缺席=默认.
放置属性( A)data-side, (中文(简体) ), data-align, (中文(简体) ), data-side-offset, (中文(简体) ), data-align-offset控制( )
相对于活动触发器的视图端口位置 :
start- 用触发左边缘对齐视图左边缘( 默认)center- 以触发器为中心取景口end- 对接右侧取景口和右侧取景口
可设定为:
navigation-menu-content(最高优先,每组)navigation-menu-itemnavigation-menuroot (最低优先级, 全球默认)
navigation-menu-positioner 是犬形弹出定位槽。 内容 data-side 编号 :
data-align 是镜像输出值,不用作放置输入.
navigation-menu-viewport-positioner 仍被接受为遗产的别名.
<!-- Faster hover response with focus auto-open opt-in -->
<nav data-slot="navigation-menu" data-delay-open="100" data-open-on-focus="true">
...
</nav>
<!-- Center-align a narrow submenu under its trigger -->
<li data-slot="navigation-menu-item" data-value="company" data-align="center">
<button data-slot="navigation-menu-trigger">Company</button>
<div data-slot="navigation-menu-content">
<a href="/about">About</a>
<a href="/careers">Careers</a>
</div>
</li>
输出属性
| 表面 | 属性 |
|---|---|
| 根号 | data-state="open|closed", (中文(简体) ), data-open, (中文(简体) ), data-closed |
| 定位器 | data-state="open|closed", (中文(简体) ), data-open, (中文(简体) ), data-closed, (中文(简体) ), data-side, (中文(简体) ), data-align, (中文(简体) ), data-instant |
| 弹出 | data-state="open|closed", (中文(简体) ), data-open, (中文(简体) ), data-closed, (中文(简体) ), data-side, (中文(简体) ), data-align, (中文(简体) ), data-starting-style, (中文(简体) ), data-ending-style, (中文(简体) ), data-instant |
| 视图 | data-state="open|closed", (中文(简体) ), data-open, (中文(简体) ), data-closed, (中文(简体) ), data-side, (中文(简体) ), data-align, (中文(简体) ), data-starting-style, (中文(简体) ), data-ending-style, (中文(简体) ), data-instant |
| 内容 | data-state="active|inactive", (中文(简体) ), data-open, (中文(简体) ), data-closed, (中文(简体) ), data-side, (中文(简体) ), data-align, (中文(简体) ), data-starting-style, (中文(简体) ), data-ending-style, (中文(简体) ), data-activation-direction="left|right" |
data-activation-direction 仅在打开顶级面板之间切换时被放出.
完全接近是故意非方向性的.
选项
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
delayOpen | number | 0 | 悬浮开始前的延迟( 毫秒) |
delayClose | number | 0 | 关闭鼠标休假前的延迟( 毫秒) |
openOnFocus | boolean | false | 聚焦触发是否打开其内容 |
mountStrategy | "lazy" | "eager" | "lazy" | 切除不活动面板或保持其连接和隐藏 |
side | "top" | "right" | "bottom" | "left" | "bottom" | 相对于触发的视图端 |
align | "start" | "center" | "end" | "start" | 在横轴上查看端口对齐 |
sideOffset | number | 0 | 从触发到取景口的距离( px) |
alignOffset | number | 0 | 交叉轴对齐相抵 (px) |
positionMethod | "absolute" | "fixed" | "absolute" | 共享弹出位置的定位策略 |
safeTriangle | boolean | false | 启用悬空安全三角切换保护 |
onValueChange | (value: string | null) => void | undefined | 活动项目更改时召回 |
debugSafeTriangle | boolean | false | 显示红色悬浮安全三角调试覆盖 |
内容安装和服务器渲染
默认情况下,导航菜单会从页面的 DOM 中删除其已关闭的面板. 这个 初始化后保留大菜单较小的页面。 菜单按钮和 这些面板以外的链接留在页面中.
打开一个面板将相同的内容放回页面中. 其状态和活动 听众被保存下来。 当切换面板时,在 前一个完成它的退出动画。 上次动画之后 面板被删除.
关闭菜单等待面板及其周围弹出完成 出道动画. 在出局动画期间重新打开一个面板,保留在页面上.
大多数应用程序可以不作任何修改地使用此默认值.
如果您的代码需要在封闭面板内找到或更新链接—— 例如,
使用 querySelector——使用 eager 在 DOM 中保留面板的模式 :
createNavigationMenu(root, { mountStrategy: "eager" });
您还可以添加 data-mount-strategy="eager" 转到导航菜单根。 A 类
JavaScript 选项优先于 HTML 属性.
默认 lazy 模式, DOM 查询不会找到关闭的面板或链接.
在初始化导航菜单和
稍后使用这个参考.
没有 JavaScript 的服务器渲染和页面
懒散的升起 没有 减少发送给浏览器的 HTML 。 面板内容是 仍然包含在您的 HTML; 导航菜单从 DOM 中删除已关闭的面板 在JavaScript初始化后.
在 JavaScript 负载或它从未运行之前, 确保必要的导航工作有效 .
您可以在初始化之前将链接保留在可见位置, 或者提供单独的倒置
如果您的面板开始隐藏, 则导航 。 也没有 lazy 也没有 eager 模式提供
自动回落.
主计长
| 方法/财产 | 说明 |
|---|---|
open(value) | 打开特定项目 |
close() | 关闭菜单 |
value | 目前活动项目值( 只读) string | null(中文(简体) ) |
destroy() | 清理所有事件听众 |
主计长销毁
destroy() 永久处理控制器并隐藏任何打开的表面,而不包含
产生额外的变化事件。 重复销毁是安全的
旧控制器变成无操作器。 在同一根上创建新控制器以重新组合 .
活动
境外事件
通过自定义事件聆听更改 :
element.addEventListener("navigation-menu:change", (e) => {
console.log("Active item:", e.detail.value);
});
入境事件
通过事件控制导航菜单 :
| 活动 | 细节 | 说明 |
|---|---|---|
navigation-menu:set | { value: string | null } | 设置活动项目或关闭菜单 |
// Open a specific item
element.dispatchEvent(
new CustomEvent("navigation-menu:set", { detail: { value: "products" } })
);
// Close the menu
element.dispatchEvent(
new CustomEvent("navigation-menu:set", { detail: { value: null } })
);
样式
navigation-menu-portal 移动到 document.body 并打开。 如果创建了弹出式插槽
它们被重新使用。 否则,就不见了 portal 编号 : positioner 编号 : popup 包装器是
在打开和关闭时生成.
运行时几何由 navigation-menu-positioner数字 : position, (中文(简体) ), top, (中文(简体) ), left, (中文(简体) ), width, (中文(简体) ),
财务报告和审定财务报表 height 被写入内并重置在关闭处. navigation-menu-popup 是犬科动物
动画外壳. 活跃 navigation-menu-content 面板挂在内部
navigation-menu-viewport 并打开。 非活动面板退出后被拆卸
默认动画; 急切的面板返回原标记位置 .
使用 positionMethod: "fixed" 或者说 data-position-method="fixed" 当菜单需要视图端口时
锚地,如内粘相头.
基本结构
/* Hidden by default */
[data-slot="navigation-menu-content"] {
display: none;
}
[data-slot="navigation-menu-content"][data-open] {
display: block;
}
/* Positioner owns placement geometry */
[data-slot="navigation-menu-positioner"],
[data-slot="navigation-menu-viewport-positioner"] {
top: 0;
left: 0;
transition: top 0.3s, left 0.3s;
}
/* Skip initial position animation */
[data-slot="navigation-menu-positioner"][data-instant],
[data-slot="navigation-menu-viewport-positioner"][data-instant] {
transition: none;
}
/* Popup owns the main shell animation */
[data-slot="navigation-menu-popup"] {
transform-origin: var(--transform-origin);
width: var(--popup-width);
height: var(--popup-height);
transition: transform 0.3s, width 0.3s, height 0.3s, opacity 0.15s;
}
[data-slot="navigation-menu-popup"][data-starting-style],
[data-slot="navigation-menu-popup"][data-ending-style] {
opacity: 0;
}
/* Viewport keeps backward-compatible sizing aliases */
[data-slot="navigation-menu-viewport"] {
width: var(--viewport-width);
height: var(--viewport-height);
}
/* Skip animation on initial open */
[data-slot="navigation-menu-viewport"][data-instant] {
transition: none;
}
/* Indicator positioning */
[data-slot="navigation-menu-indicator"] {
position: absolute;
left: var(--indicator-left);
width: var(--indicator-width);
transition: left 0.2s, width 0.2s;
}
data-instant 用于初始开放阶段和同步驱动锚地跟踪更新
(例如,当一个粘性触发器在菜单打开时移动). 切换时可以清除,
关闭, 或者在跟踪更新后解决。 使用它来跳过这些重新定位的转换,而无需
压制出站动画.
动画
使用 data-starting-style 编号 : data-ending-style 打开 navigation-menu-popup 完全弹出
打开/关闭动画 navigation-menu-content 用于面板存在.
方向面板切换应关闭密钥 data-activation-direction="left|right" 内容.
活动面板保持正常流;挂载的不活动/出行面板绝对定位
以运行时间表示,这样它们不会在激活时影响弹出测量.
对于出局动画,请避免CSS即刻强制加码内容 data-state
(例如 display: none 在非活性面板上),因为这绕过存在生命周期.
[data-slot="navigation-menu-popup"][data-starting-style],
[data-slot="navigation-menu-popup"][data-ending-style] {
opacity: 0;
transform: scale(0.96);
}
[data-slot="navigation-menu-content"][data-starting-style],
[data-slot="navigation-menu-content"][data-ending-style] {
opacity: 0;
}
[data-slot="navigation-menu-content"][data-starting-style][data-activation-direction="right"] {
transform: translateX(2rem);
}
[data-slot="navigation-menu-content"][data-starting-style][data-activation-direction="left"] {
transform: translateX(-2rem);
}
[data-slot="navigation-menu-content"][data-ending-style][data-activation-direction="right"] {
transform: translateX(-2rem);
}
[data-slot="navigation-menu-content"][data-ending-style][data-activation-direction="left"] {
transform: translateX(2rem);
}
遗产 data-motion 财务报告和审定财务报表 --motion-direction 在面板切换后向后仍会释放
兼容性。 包括根层和内容层 data-motion 输出,但
data-activation-direction 是犬形方向钩.
--popup-width 编号 : --popup-height 是弹出壳大小的Vars。 菜单打开后,他们就留下来
在固定像素值下, CSS 可以直接将面板到平面板的大小变化 px 目标.
初始打开时同步写入测量大小; shell 不需要 auto 重置时
打开.
CSS 变量
| 变量 | 元素 | 说明 |
|---|---|---|
--popup-width | 弹出 | 打开时弹出宽度; CSS 可以在像素值之间对 shell 宽度进行动画化 |
--popup-height | 弹出 | 打开时弹出高度; CSS 可以在像素值之间对 shell 高度进行动画化 |
--positioner-width | 定位器 | 活动面板的测量宽度 |
--positioner-height | 定位器 | 活动面板的测量高度 |
--available-width | 定位器 | 活动触发器和视图边缘之间的可用宽度 |
--available-height | 定位器 | 活动触发器和视图边缘之间的可用高度 |
--transform-origin | 弹出/取景口/内容/位置 | 锁定像素源以触发( S)side + 键 align),范围为每个元素的坐标空间 |
--viewport-width | 视图 | 活动面板宽度的遗留别名 |
--viewport-height | 视图 | 活动面板高度的后遗症别名 |
--indicator-left | 指标 | 从列表中向左偏移 |
--indicator-width | 指标 | 悬浮起子的宽度 |
--indicator-top | 指标 | 从列表中乘以顶 |
--indicator-height | 指标 | 悬浮起落器高度 |
--motion-direction | 视图 | 遗留切换方向输出 : 1 (权利)或 -1 (左边) |
折旧兼容性
navigation-menu-viewport-positioner是一个被折旧的别名,用于navigation-menu-positioner。 。 。 .--viewport-width, (中文(简体) ),--viewport-height根/内容data-motion,以及--motion-direction将在下一次主要释放中进行折旧并计划清除.- 内容已包装
navigation-menu-portal编号 :navigation-menu-positioner贝壳是只恢复相容的,也计划在下个主放出时被移除.
键盘导航
在顶级项目内
| 密钥 | 行动 |
|---|---|
ArrowLeft | 将焦点移动到上一个顶级项目( 子菜单触发器或纯链接) |
ArrowRight | 将焦点移动到下一个顶级项目( submenu 触发器或纯链接) |
Tab | 按 DOM 顺序将焦点移动到下一个顶级项目 |
Shift+Tab | 以反向 DOM 顺序将焦点移动到上一个顶级项目 |
ArrowDown | 将焦点移动到内容面板( 仅在焦点项目有子菜单内容时) |
Home | 将焦点移动到第一个顶级项目 |
End | 将焦点移动到上一个顶级项目 |
Escape | 关闭菜单 |
顶级子菜单触发器和平面链接仍保留在天然标签顺序中.
在内容小组内
| 密钥 | 行动 |
|---|---|
ArrowDown 编号 : ArrowRight | 移动到下一个可聚焦元素 |
ArrowUp 编号 : ArrowLeft | 移动到上一个元素( 启动时返回触发) |
Tab | 从上一个内容项中, 移动焦点到下个顶级 Nav项; 如果没有, 移动到 nav root 之后的下个可焦点项 |
Shift+Tab | 从第一个内容项目, 将焦点移回自有触发器 |
Escape | 关闭菜单并返回焦点以触发 |
行为
- 缓冲: 打开
delayOpen毫秒后关闭delayClose分钟 - 点击: 锁定菜单打开直至明确动作为止(单击同一触发器,单击另一个触发器,点击外部,或
Escape); 盘旋在锁定时不切换/关闭 - 焦点: 默认不自动打开; 设置
openOnFocus编号 :data-open-on-focus="true"选择加入 - 触发打开焦点数字 :
- 指针点击/tap 保持对触发器的关注
- 键盘激活/程序点击将焦点移入菜单内容(第一个可聚焦项目,或内容面板倒置)
- 指标: 当没有子菜单打开时, 普通顶级链接参与指标定位; 打开子菜单状态优先
- 切换: 项目之间的即时过渡(无延迟)
许可证
麻省理工学院