You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Nunjucks从JSON生成多层级HTML链接列表?(11ty访问对象孙节点)

解决Eleventy+Nunjucks多层导航渲染问题

问题背景

我正在搭建作品集网站,使用以下JSON结构定义导航菜单:

{
    "navTree": [
        {
            "lvl1Item": "Graphic Design",
            "lvl1Link": "/graphic-design",
            "hasLvl2Items": true,
            "lvl2Items": [
                {
                    "lvl2Item": "Logos",
                    "lvl2Link": "/logos"
                },
                {
                    "lvl2Item": "Digital Graphics",
                    "lvl2Link": "/digital"
                }
            ]
        },
        {
            "lvl1Item": "Illustration",
            "lvl1Link": "/illust",
            "hasLvl2Items": false,
            "lvl2Items": null
        },
        {
            "lvl1Item": "Character Design",
            "lvl1Link": "/characters",
            "hasLvl2Items": false,
            "lvl2Items": null
        }
    ]
}

期望渲染出的多层级HTML导航菜单如下:

<ul>
  <li><a href="/graphic-design" class="sidenav-lvl1">Graphic Design</a></li>
  <ul>
    <li><a href="/graphic-design/logos" class="sidenav-lvl2">Logos</a></li>
    <li><a href="/graphic-design/digital" class="sidenav-lvl2">Digital Graphics</a></li>
  </ul>
  <li><a href="/illust" class="sidenav-lvl1">Illustration</a></li>
  <li><a href="/characters" class="sidenav-lvl1">Character Design</a></li>
</ul>

当前问题

编写的Nunjucks代码无法正确渲染二级菜单:

<ul>
  {% for lvl1Item in navTree %}
    <li>
      <a href="{{ lvl1Item.lvl1Link }}" class="sidenav-lvl1">{{ lvl1Item.lvl1Label }}</a>
      <ul>
        {% if lvl1Item.hasLvl2Items %}
          <li>Lvl 2 True! {# Just testing to see if it found anything. #}</li>
          {% for lvl2Items in lvl1Item %}
          <li>
            <a href="{{ lvl1Item.lvl1Link }}/{{ lvl1Item.lvl2Items.lvl2Link }}" class="sidenav-lvl2">{{ lvl1Item.lvl2Items.lvl2Label }}</a>
          </li>
          {% endfor %}
        {% endif %}
      </ul>
    </li>
  {% endfor %}
</ul>

实际输出的HTML仅能检测到二级菜单存在,但无法显示内容:

<ul>
  <li>
    <a href="/graphic-design" class="sidenav-lvl1">Graphic Design</a>
    <ul>
      <li>Lvl 2 True! {# Just testing to see if it found anything. #}</li>
    </ul>
  </li>
  <li>
    <a href="/illust" class="sidenav-lvl1">Illustration</a>
    <ul></ul>
  </li>
  <li>
    <a href="/characters" class="sidenav-lvl1">Character Design</a>
    <ul></ul>
  </li>
</ul>

问题原因与修复

代码存在两个核心错误:

  1. 循环目标错误:二级菜单循环时遍历的是lvl1Item整个对象,而非其下的lvl2Items数组。
  2. 字段名与访问路径错误:JSON中的文本字段是lvl2Item,但代码中误用了lvl2Label;同时访问二级属性时,应使用循环变量而非直接从lvl1Item.lvl2Items取值。

修正后的Nunjucks代码

<ul>
  {% for lvl1 in navTree %}
    <li>
      <a href="{{ lvl1.lvl1Link }}" class="sidenav-lvl1">{{ lvl1.lvl1Item }}</a>
      {% if lvl1.hasLvl2Items and lvl1.lvl2Items %}
        <ul>
          {% for lvl2 in lvl1.lvl2Items %}
            <li>
              <a href="{{ lvl1.lvl1Link }}{{ lvl2.lvl2Link }}" class="sidenav-lvl2">{{ lvl2.lvl2Item }}</a>
            </li>
          {% endfor %}
        </ul>
      {% endif %}
    </li>
  {% endfor %}
</ul>

优化点说明

  • 简化循环变量名(lvl1、lvl2),提升代码可读性。
  • 增加lvl1.lvl2Items非空判断,避免null值引发的报错。
  • 修正字段名:用lvl1.lvl1Item替代错误的lvl1.lvl1Label,lvl2.lvl2Item替代lvl2.lvl2Label。
  • 调整链接拼接方式为{{ lvl1.lvl1Link }}{{ lvl2.lvl2Link }},确保路径拼接正确(如/graphic-design + /logos = /graphic-design/logos)。

更灵活的导航配置方案

若未来需要支持三级及以上菜单,可重构为递归式JSON结构,让配置更易扩展:

{
  "navTree": [
    {
      "label": "Graphic Design",
      "url": "/graphic-design",
      "children": [
        {
          "label": "Logos",
          "url": "/logos"
        },
        {
          "label": "Digital Graphics",
          "url": "/digital"
        }
      ]
    },
    {
      "label": "Illustration",
      "url": "/illust",
      "children": []
    },
    {
      "label": "Character Design",
      "url": "/characters",
      "children": []
    }
  ]
}

对应的递归Nunjucks宏(可复用):

{% macro renderNav(items, parentUrl = "") %}
  <ul>
    {% for item in items %}
      <li>
        <a href="{{ parentUrl }}{{ item.url }}" class="{{ parentUrl ? 'sidenav-lvl2' : 'sidenav-lvl1' }}">{{ item.label }}</a>
        {% if item.children and item.children.length > 0 %}
          {{ renderNav(item.children, parentUrl + item.url) }}
        {% endif %}
      </li>
    {% endfor %}
  </ul>
{% endmacro %}

{# 调用宏生成导航 #}
{{ renderNav(navTree) }}

该方案无需手动判断层级,新增层级时仅需在JSON中添加children数组即可,维护成本更低。

内容的提问来源于stack exchange,提问作者HikaTamika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:06:00