跳到主要内容
  1. Skills/
  2. Hugo 使用指南/

在hugo中如何使用菜单

·字数 1574·4 分钟
howto

hugo 提供了比较灵活的菜单生成方案。分为内置模式、或自定义模式。自定义模块就是用户根据自己的需要自行去生成导航栏。本文主要是分享在使用hugo内置模式菜单的使用经验。

官方的文档链接, gohugo.io/content-management/menus/ 。看完文档后有没有一种云里雾的感觉呢?

如果你也跟我一样,有这种感觉,那么说明不是你的问题,因为hugo的菜单支持比较灵活,分了好几个文档,需要结合来看。当你做为例子之后,那么一切都会变得简单。

其实 hugo 的菜单相关文档有这些:

  • gohugo.io/content-management/menus, 介绍如何管理菜单
  • gohugo.io/templates/menu-templates,在模板中使用菜单的示例
  • gohugo.io/variables/menus, 在模板中使用菜单里的对象,这个对象决定了在模板或者 config.yaml 中可以获取或者配置什么信息

菜单对象 #

Menu Entry Properties

在了解如果配置菜单或在模板中使用菜单之前,需要先了解 hugo 为菜单设计了哪些信息项,即数据结构。 主要的是这些,名称(name, title identifier)、url、优先权重(weight)、上级菜单、下级菜单、对应页面等。可以从文档 variables/menus 上获得更多详细内容。

以上所列信息项,配置在 config.yaml 中,然后就可以在 页面模板中通过 site.Menus 获取到。

菜单辅助函数 #

hugo 为菜单对象提供了几个方便的辅助函数,如:

MENUENTRY.HasChildren
判断是否有下级菜单
MENUENTRY.KeyName
返回菜单的标识
MENUENTRY.Title
用于菜单页面显示
PAGE.IsMenuCurrent MENU MENUENTRY
判断页面是否为某个菜单对应的页面
PAGE.HasMenuCurrent MENU MENUENTRY
判断页面是否为某个菜单下的子菜单对应页面

以上函数,比较常用的是.HasChildren.Title

菜单信息配置 #

hugo 中,可以有两种方式来配置菜单信息。

  • config.yaml 中添加 menus.MENU.[MENUENTRY,MENUENTRY] 项
  • 在 页面内容文章 xxx.mdfront matter 中配置菜单子项

结合以上两种方式,可以满足非内容页面的链接与内容页面的链接。

youwu.today 提示,因为 hugo 的配置器非常灵活,支持将菜单的信息配置在config.yaml之外的menus.yaml文件中,为了方便维护管理,本站使用 menus.yaml 文件来管理本站使用到的菜单。

配置文件支持 json、yaml、toml 格式。为了方面阅读,本文使用 yaml 格式。

一个正常的 config.yaml 菜单项大概长这个样子,以本站菜单配置中的一段为例:

# menus.yaml
main:
  - name: hugo section 技能
    title: 有悟
    url: /skill/
    weight: 2
    identifier: skill
    params:
      type: grid
...

一个菜单项就是一个 MENUENTRY。其中最重要的 identifierurl。而示例中的 main 可以是任何标识符,因为 hugo 并没有限定这个名称。你可以把它简单理解 为菜单组的名称。另外,为了某种判断,可以加上自定义参数,这些参数 hugo 是无法理解的,所以要统一放在 params 中,由用户自行决定。

如果你将菜单信息配置在 config.yaml 中,那么 yaml 中应该这样写:

# config.yaml
menu:
    main:
      - name: hugo section 技能
        title: 有悟
        url: /skill/
        weight: 2
        identifier: skill
        params:
          type: grid
...

将页面链接做为子菜单 #

在页面内容文件的 front matter 中,配置子菜单:

# front matter
...
menu: 
  main:
    parent: "skill"
...

这里之所以产生菜单父子关联关系,是 mainparent 起了作用。这两项结合指向了 config.yaml 或者 menus.yaml 中的对应的菜单。就这样,hugo 会在 skill MENUENTRY 下面挂上一个子菜单,来对应这个页面。

直接配置子菜单 #

除了可以在内容文件的 front matter 挂接子菜单外,还可以直接在 config.yaml 配置子菜单。继续上面的示例:

# menus.yaml
main:
  - name: hugo section 技能
    title: 有悟
    url: /skill/
    weight: 2
    identifier: skill
    params:
      type: grid
  - name: 今日热点、热榜聚集
    title: 今日
    url: /hot/
    weight: 1 
    identifier: hot
  - name: 热搜
    title: 热搜
    url: /hot/words/
    identifier: hot_words
    parent: hot
    weight: 101 
...

这一段 yaml 片段,hugo 会生成如下结构的菜单,重点在于 parent 属性。

main
├─ skill
├─ hot
│  └─ hot_words

如果你将子菜单如 hot_words 配置在 menus.yaml中,那么 front matter 中就不要配置,因为会重复。

在模板中引用菜单信息 #

在配置了菜单信息之后,如果不在模板中使用,是起不到任何作用的。

<ul>
{{ range site.Menus.main }}
    {{ if .HasChildren }}
        <ul>
        {{ range .Children }}
            <li>
                <a href="{{ .URL }}">{{ .Name }}</a>
            </li>
         {{ end }}
        </ul>
    {{ else }}
    <li>
         <a href="{{ .URL }}">{{ .Name }}</a>
    </li>
    {{ end }}
{{ end }}
</ul>

例中的 site.Menus.main 就是在模板中获取 menus.yamlmain 的方法。这个例子可以获取到 直接配置子菜单 中的 skillhot ,并且菜单项 hot.HasChildren 可以判断存在子菜单,使用 .Children 可以取到 hot_words,当然 .Children 得到的是一个 slice,需要 range 来迭代。

gohugo.io/templates/menu-templates/ 上有更加详尽的例子。