ThinkTemplate 循环调用多级子栏目(顶级、二级、三级)
求元工坊CMS 通过 GlobalView 中间件将栏目树注入到所有前台模板,模板中直接使用 $navList 变量即可循环调用多级子栏目(顶级栏目下二级、三级...N级栏目)。
栏目树 | 多级子栏目循环调用
求元工坊CMS 的栏目数据以树形结构存储,子栏目存放在父级栏目的 children 键中,通过 volist 嵌套即可逐级展开。
一、栏目树数据结构
$navList 是一个多维数组,每个栏目包含以下字段:
| 字段 | 说明 |
|---|---|
id | 栏目ID |
name | 栏目名称 |
alias | 栏目别名(如 home/doc) |
url | 栏目链接(已生成绝对地址) |
cate_type | 栏目类型(1文章、5图片等) |
children | 子栏目数组(无子栏目时为 null) |
二、调用顶级(一级)栏目
2.1 基本写法
{volist name="navList" id="nav"}
<li><a href="{$nav.url}">{$nav.name}</a></li>
{/volist}
注解:$navList 本身就是顶级栏目数组,直接 volist 遍历即可输出一级导航。
2.2 带当前栏目高亮
{volist name="navList" id="nav"}
<li>
<a href="{$nav.url}" {if condition="isset($current_cate_id) && $current_cate_id == $nav['id']"}class="active"{/if}>
{$nav.name}
</a>
</li>
{/volist}
注解:通过 $current_cate_id(由控制器传入)判断当前栏目,添加 active 高亮样式。
三、循环调用二级子栏目
3.1 基本写法(volist 嵌套)
{volist name="navList" id="nav"}
<li>
<a href="{$nav.url}">{$nav.name}</a>
<!-- 二级子栏目开始 -->
{if condition="!empty($nav['children'])"}
<ul class="sub-menu">
{volist name="nav['children']" id="child"}
<li><a href="{$child.url}">{$child.name}</a></li>
{/volist}
</ul>
{/if}
<!-- 二级子栏目结束 -->
</li>
{/volist}
注解:外层 volist 遍历顶级栏目,内层 volist 遍历 $nav['children'] 输出二级子栏目。使用 !empty() 判断避免空数组报错。
3.2 简化写法(不判断空值)
{volist name="navList" id="nav"}
<li>
<a href="{$nav.url}">{$nav.name}</a>
{volist name="nav['children']" id="child"}
<ul>
<li><a href="{$child.url}">{$child.name}</a></li>
</ul>
{/volist}
</li>
{/volist}
注意:当 children 为 null 时,volist 不会执行循环体,但会输出空的 <ul> 标签。建议始终加上 !empty() 判断。
四、循环调用三级(及更多级)子栏目
4.1 三级栏目写法
{volist name="navList" id="nav"}
<li>
<a href="{$nav.url}">{$nav.name}</a>
<!-- 二级子栏目开始 -->
{if condition="!empty($nav['children'])"}
<ul class="sub-menu">
{volist name="nav['children']" id="child"}
<li>
<a href="{$child.url}">{$child.name}</a>
<!-- 三级子栏目开始 -->
{if condition="!empty($child['children'])"}
<ul class="sub-sub-menu">
{volist name="child['children']" id="grandchild"}
<li><a href="{$grandchild.url}">{$grandchild.name}</a></li>
{/volist}
</ul>
{/if}
<!-- 三级子栏目结束 -->
</li>
{/volist}
</ul>
{/if}
<!-- 二级子栏目结束 -->
</li>
{/volist}
注解:三级栏目存放在二级栏目的 children 中,通过 $child['children'] 继续下钻。理论上支持无限级嵌套,但建议导航菜单最多展示三级。
五、实际应用场景
5.1 顶部导航菜单(带下拉)
<nav class="main-nav">
<ul class="nav-list">
{volist name="navList" id="nav"}
<li class="nav-item {if condition="!empty($nav['children'])"}has-children{/if}">
<a href="{$nav.url}">{$nav.name}</a>
{if condition="!empty($nav['children'])"}
<ul class="dropdown">
{volist name="nav['children']" id="child"}
<li><a href="{$child.url}">{$child.name}</a></li>
{/volist}
</ul>
{/if}
</li>
{/volist}
</ul>
</nav>
5.2 侧边栏栏目树
<aside class="sidebar">
<div class="cate-tree">
{volist name="navList" id="nav"}
<div class="tree-node">
<a href="{$nav.url}" class="node-link">{$nav.name}</a>
{if condition="!empty($nav['children'])"}
<div class="tree-children">
{volist name="nav['children']" id="child"}
<a href="{$child.url}" class="child-link">{$child.name}</a>
{if condition="!empty($child['children'])"}
<div class="tree-grandchildren">
{volist name="child['children']" id="grandchild"}
<a href="{$grandchild.url}" class="grandchild-link">{$grandchild.name}</a>
{/volist}
</div>
{/if}
{/volist}
</div>
{/if}
</div>
{/volist}
</div>
</aside>
5.3 面包屑导航
<div class="breadcrumb">
<a href="{$siteWww}/">首页</a>
{if condition="isset($breadcrumb)"}
{volist name="breadcrumb" id="crumb"}
<span class="separator">></span>
<a href="{$crumb.url}">{$crumb.name}</a>
{/volist}
{/if}
</div>
注解:面包屑数据由控制器传入,格式为 ['首页' => '/', '文档' => '/doc', 'ThinkTemplate' => '/doc/thinktemplate']。
六、注意事项
- 始终判断 children 是否为空:使用
!empty($item['children'])判断,避免输出空的<ul>标签或报错。 - 字段访问使用数组下标:在 volist 嵌套中,子栏目字段使用
{$child['name']}而非{$child.name}。 - url 字段已生成绝对地址:GlobalView 中间件已处理
url字段,直接输出即可,无需再调用site_url()。 - 层级变量命名建议:一级用
nav、二级用child、三级用grandchild,避免命名冲突。 - 建议最多展示三级:导航菜单层级过深会影响用户体验,建议超过三级的栏目通过列表页展示。
七、与 XYHCMS 的对比
| 特性 | 求元工坊CMS | XYHCMS |
|---|---|---|
| 栏目标签 | 全局变量 $navList | 自定义标签 <yang:catlist> |
| 子栏目字段 | children | child |
| 循环标签 | {volist} | <volist> 或 <foreach> |
| URL 获取 | 直接输出 {$nav.url} | 需过滤器 {$v|get_url} |
| 无限级支持 | 理论上支持 | 需手动嵌套 |
本文档适用于求元工坊CMS v1.0 及以上版本。更多模板语法请参考 ThinkTemplate SSR 数据渲染指南、模板算术运算符使用指南 和 模板条件判断语句(if 标签)。