导航菜单

本页内容

菜单允许编辑者在不更改站点模板的情况下管理有序链接。菜单有一个稳定的名称,如 primary 或 footer,每个翻译菜单有一组单独的项目。

创建菜单

在 EmDash 管理面板的 Menus 中创建和排列菜单。

  1. 点击 Create Menu 并输入名称和标签。模板查询名称,而标签在管理面板中标识菜单。

  2. 点击 Add Content 链接一个条目,或点击 Add Custom Link 输入外部 URL 或根相对站点路径。

  3. 使用 Move up 和 Move down 设置顺序。编辑项目并选择 Parent 来嵌套它。

在每个语言中使用相同的菜单名称。在多语言站点上,打开菜单并使用其 Translations 面板创建和编辑其他语言版本。EmDash 保持相同内容或分类术语的翻译相互连接,因此 getMenu() 可以使用请求语言的标签和 slug。

菜单链接如何解析

内容和分类菜单项存储的是引用而非完成的 URL。当模板调用 getMenu() 时,EmDash 使用当前集合和语言数据解析该引用。

菜单项类型返回给模板的 URL
内容条目集合的 urlPattern,或当集合没有模式时为 /{collection}/{slug}
分类术语使用解析的术语翻译的 /{taxonomy}/{slug}
集合归档/{collection}/
自定义链接编辑者输入的外部 URL 或根相对路径

每个返回的项目还包含其标签、可选目标、title 属性、CSS 类和嵌套的 children。下面的渲染示例直接使用这些值。

渲染菜单

在服务器渲染的 Astro 组件中调用 getMenu()。当名称不存在时返回 null。

以下布局渲染一个主菜单和一级嵌套项目:

---
import { getMenu } from "emdash";
import { getRelativeLocaleUrl } from "astro:i18n";

const locale = Astro.currentLocale;
const menu = await getMenu("primary", { locale });

function menuHref(url: string) {
  return locale && url.startsWith("/")
    ? getRelativeLocaleUrl(locale, url)
    : url;
}
---

{menu && menu.items.length > 0 && (
  <nav aria-label="主导航">
    <ul>
      {menu.items.map((item) => {
        const href = menuHref(item.url);

        return (
          <li class:list={item.cssClasses}>
            <a
              href={href}
              target={item.target}
              rel={item.target === "_blank" ? "noopener noreferrer" : undefined}
              title={item.titleAttr}
              aria-current={Astro.url.pathname === href ? "page" : undefined}
            >
              {item.label}
            </a>

            {item.children.length > 0 && (
              <ul>
                {item.children.map((child) => {
                  const childHref = menuHref(child.url);

                  return (
                    <li class:list={child.cssClasses}>
                      <a
                        href={childHref}
                        target={child.target}
                        rel={child.target === "_blank" ? "noopener noreferrer" : undefined}
                        title={child.titleAttr}
                        aria-current={Astro.url.pathname === childHref ? "page" : undefined}
                      >
                        {child.label}
                      </a>
                    </li>
                  );
                })}
              </ul>
            )}
          </li>
        );
      })}
    </ul>
  </nav>
)}

getMenu() 首先选择显式的 locale,然后是当前请求语言,最后是配置的默认语言。如果该语言中缺少菜单或引用的条目,查找将遵循配置的回退链。

菜单项 URL 包含集合 URL 模式或分类路径,但不包含 Astro 的语言前缀。menuHref() 辅助函数将该前缀添加到根相对链接,并保持外部链接不变。

此示例渲染一级子项,涵盖典型的下拉菜单。如果编辑者可以创建更深层的导航,请将项目标记移到一个递归组件中,该组件使用相同规则渲染每个项目的 children。

在小部件区域中使用菜单

菜单小部件将现有菜单放置在小部件区域内。小部件读取当前请求语言的菜单。当站点需要自定义嵌套标记或显式语言 URL 处理时,使用上面的直接渲染模式。

直接查询菜单数据

当模板需要可用的菜单定义而不是一个菜单的项目时,使用 getMenus()。运行时 API 参考记录了查询签名和返回值。

对于编程式菜单更改,使用 Bearer 令牌进行身份验证,并在每个状态更改请求中添加 X-EmDash-Request: 1。请参阅菜单端点了解请求体和响应。

请参阅国际化了解语言路由和回退配置。