准备工作:理解Dede的栏目结构
在调用之前,您需要了解Dede的栏目结构:

(图片来源网络,侵删)
- 顶级栏目 (Top-level):没有父栏目的栏目,其
topid字段为 0。 - 子栏目 (Sub-level):有父栏目的栏目,其
reid字段指向父栏目的 ID。
调用多级栏目的核心就是利用 reid 和 topid 这两个字段以及 channel 标签的 typeid 和 reid 属性来遍历层级关系。
递归调用(最常用、最灵活)
这是实现无限级栏目调用的标准方法,它通过一个子模板(嵌套标签)来循环调用自身,从而实现层级的无限展开。
场景:生成一个完整的、可展开折叠的导航菜单。
创建一个子模板文件 sub_nav.htm
这个文件用来递归地输出子栏目。

(图片来源网络,侵删)
{dede:channel type='son' currentstyle='
<li class="active"><a href=~typelink~ target="_self">~typename~</a></li>
'}
<li>
<a href="[field:typelink/]" title="[field:typename/]">[field:typename/]</a>
{dede:channel type='son' noself='yes'}
<!-- 如果有子栏目,则递归调用自己 -->
<ul class="sub-nav">
{dede:include filename='sub_nav.htm'/}
</ul>
{dede:channel}
</li>
{/dede:channel}
代码解释:
{dede:channel type='son' ...}:type='son'表示调用当前栏目的直接子栏目。noself='yes': 不输出当前栏目本身,只输出其子栏目。{dede:include filename='sub_nav.htm'/}: 这是递归的核心,它包含了sub_nav.htm自身,只要子栏目存在,这个循环就会一直进行下去,直到最后一层没有子栏目为止。
在主模板文件中调用
假设你的主模板是 head.htm,你想要在某个位置放置导航栏。
<ul class="main-nav">
{dede:channel type='top' currentstyle='
<li class="active"><a href=~typelink~ target="_self">~typename~</a></li>
'}
<li>
<a href="[field:typelink/]" title="[field:typename/]">[field:typename/]</a>
{dede:channel type='son' noself='yes'}
<ul class="sub-nav">
{dede:include filename='sub_nav.htm'/}
</ul>
{dede:channel}
</li>
{/dede:channel}
</ul>
代码解释:
{dede:channel type='top' ...}:type='top'表示调用所有顶级栏目(topid=0的栏目)。currentstyle: 这是Dede标签的强大功能,当栏目与当前页面栏目匹配时,会使用currentstyle里的代码。~typename~和~typelink~是currentstyle里的特殊写法,会被替换为栏目名和链接。- 对于每个顶级栏目,我们都检查它是否有子栏目(通过内层的
{dede:channel type='son'}),如果有,就加载sub_nav.htm子模板来渲染子菜单。
指定父栏目调用子栏目
如果你只想调用某一个特定栏目的所有子栏目(包括多级),可以使用 typeid 属性。
场景:调用 ID 为 2 的栏目的所有子栏目。
<ul>
{dede:channel typeid='2' type='son'}
<li>
<a href="[field:typelink/]" title="[field:typename/]">[field:typename/]</a>
</li>
{/dede:channel}
</ul>
代码解释:
typeid='2': 指定父栏目的 ID。type='son': 调用该父栏目的直接子栏目。- 注意:这个默认只调用直接子栏目,不会递归调用孙栏目,如果需要递归,仍然需要结合方法一的子模板。
调用指定层级的栏目
如果你只想调用某一层级的所有栏目(所有二级栏目),可以使用 channel 标签的 topid 属性。
场景:调用所有顶级栏目下的直接子栏目(即所有二级栏目)。
<ul>
{dede:channel type='top' currentstyle='
<li class="active"><a href=~typelink~ target="_self">~typename~</a></li>
'}
{dede:channel type='son' noself='yes'}
<li>
<a href="[field:typelink/]" title="[field:typename/]">[field:typename/]</a>
</li>
{dede:channel}
{/dede:channel}
</ul>
代码解释:
- 外层
{dede:channel type='top'}先循环所有顶级栏目。 - 对于每一个顶级栏目,内层
{dede:channel type='son' noself='yes'}调用它的直接子栏目(即二级栏目)。 - 这种方式可以清晰地展示出二级栏目的结构,但不会继续深入到三级、四级栏目。
使用SQL直接查询(高级用法)
当 channel 标签无法满足复杂需求时(需要按特定字段排序、限制数量等),可以直接使用SQL查询。
场景:调用所有顶级栏目,并按排序字段 sortrank 降序排列。
<ul>
{dede:sql sql='SELECT id,typename,typelink,typedir FROM `dede_arctype` WHERE topid=0 ORDER BY sortrank DESC'}
<li>
<a href="[field:typelink/]" title="[field:typename/]">[field:typename/]</a>
</li>
{/dede:sql}
</ul>
代码解释:
dede:sql: 自定义SQL查询标签。sql='...': 写入你的SQL语句。dede_arctype: Dede的栏目表,如果你的表前缀不是dede_,需要修改。WHERE topid=0: 只查询顶级栏目。ORDER BY sortrank DESC: 按sortrank字段降序排列。
[field:字段名/]: 在循环体内,使用field标签来输出SQL查询结果中的字段。
| 属性 | 说明 | 适用场景 |
|---|---|---|
typeid |
指定栏目ID,作为查询的起点。 | 调用指定栏目的子栏目或同级栏目。 |
topid |
指定顶级栏目的ID,topid=0 表示所有顶级栏目。 |
调用某一层级下的所有栏目。 |
reid |
指定父栏目的ID,与 typeid 类似。 |
调用指定父栏目的子栏目。 |
type |
son (子栏目), self (同级栏目), top (顶级栏目)。 |
定义调用的栏目范围。 |
currentstyle |
当前栏目高亮样式的HTML代码。 | 导航菜单,用于指示当前所在栏目。 |
row |
调用栏目数量。 | 限制显示的栏目数量。 |
noself |
yes 或 no,是否不包含调用栏目本身。 |
在调用子栏目时,常设置为 yes。 |
最佳实践建议
- 导航菜单:强烈推荐使用方法一(递归调用),因为它最灵活,能适应网站未来栏目的增减。
- 侧边栏分类:如果只是调用一个固定栏目的几级子栏目,可以使用方法二或方法三。
- 性能考虑:对于非常庞大的栏目体系,递归调用可能会有轻微的性能开销,如果对性能要求极高,可以考虑使用方法四(SQL查询)并结合缓存机制。
- CSS配合:多级栏目的展示效果(如下拉、展开)需要配合CSS样式来实现,确保你的HTML结构清晰,CSS选择器准确。
希望这份详细的指南能帮助您完美地实现Dedecms的多级栏目调用!
