核心概念
在 DedeCMS 中,栏目的层级关系是通过 topid 和 reid 这两个字段来维护的:

(图片来源网络,侵删)
reid(父栏目ID): 当前栏目的直接上级栏目ID。reid=0,则表示它是一个顶级栏目(没有父栏目)。topid(顶级栏目ID): 当前栏目所属的最顶层栏目的ID,如果一个栏目本身就是顶级栏目,那么它的topid就等于自己的id。
理解这两个字段是操作栏目的关键。
获取当前栏目的父栏目信息
这种方法适用于在内容页 (article_article.htm) 或列表页 (article_list.htm) 中,需要显示当前栏目所属的上级栏目信息。
场景:在文章页显示文章所属的“顶级栏目”名称和链接
这是最常见的需求,比如面包屑导航。
代码示例 (在模板文件中直接使用):

(图片来源网络,侵删)
{dede:field name='typeid' function="GetTopid(@me)"/}
代码解释:
{dede:field name='typeid'}: 获取当前文章所属栏目的 ID。function="GetTopid(@me)": 这是一个系统内置的函数,作用是传入一个栏目ID,返回其顶级栏目的ID。@me代表前面获取到的typeid的值。- 这段代码会输出一个数字,即顶级栏目的ID,但通常我们更需要的是栏目的名称和链接。
更实用的示例:获取顶级栏目的名称和链接
<a href="{dede:field name='typeid' function="GetTopid(@me)"/}/">{dede:field name='typeid' function="GetTopid(@me)"/}</a>
上面的代码会输出一个链接,但链接文本和地址都是ID,这显然不是我们想要的,我们需要结合 channel 标签来获取具体信息。
正确且推荐的做法:

(图片来源网络,侵删)
{dede:channel typeid='[field:topid/]'}
<a href="[field:typelink/]">[field:typename/]</a>
{/dede:channel}
代码解释:
{dede:channel}: 这是获取栏目信息的标签。typeid='[field:topid/]': 这是关键,我们通过field:topid/获取当前栏目的顶级栏目ID,并将其作为typeid参数传递给channel标签,这样,channel标签就会只查询这一个顶级栏目的信息。[field:typelink/]: 输出该顶级栏目的链接地址。[field:typename/]: 输出该顶级栏目的名称。
如果你需要获取直接父栏目(不一定是顶级栏目):
将 topid 换成 reid 即可。
{dede:channel typeid='[field:reid/]'}
<a href="[field:typelink/]">[field:typename/]</a>
{/dede:channel}
获取指定栏目的所有直接子栏目
这种方法适用于制作一个主导航栏,鼠标悬停时显示其下的所有子栏目。
场景:在首页制作一个“产品中心”的下拉菜单
假设“产品中心”栏目的ID是 2。
代码示例:
{dede:channelartlist typeid='2'}
<div class="dropdown">
<a href="{dede:field name='typeurl'/}">{dede:field name='typename'/}</a>
<ul class="sub-menu">
{dede:channel type='son' noself='yes'}
<li><a href="[field:typelink/]">[field:typename/]</a></li>
{/dede:channel}
</ul>
</div>
{/dede:channelartlist}
代码解释:
{dede:channelartlist typeid='2'}:channelartlist标签用于指定一个父栏目,并循环输出其所有子栏目。typeid='2'指定了父栏目为ID是2的“产品中心”。{dede:field name='typeurl'}和{dede:field name='typename'}: 这里输出的是父栏目“产品中心”本身的链接和名称。{dede:channel type='son' noself='yes'}: 这是获取子栏目的核心标签。type='son': 表示只获取当前栏目(由channelartlist指定的父栏目)的直接子栏目。noself='yes': 表示不获取栏目本身。
[field:typelink/]和[field:typename/]: 在循环中,输出每个子栏目的链接和名称。
获取指定栏目的所有子孙级栏目(递归获取)
如果你需要获取一个栏目下的所有层级的子栏目(获取“产品中心”下的所有分类和子分类),就需要使用递归或循环查询。
场景:制作一个完整的产品分类树状导航
假设“产品中心”栏目的ID是 2。
代码示例 (通过循环实现):
{dede:channel type='self' typeid='2'}
<h2>[field:typename/]</h2>
<ul class="category-tree">
{dede:sonlist}
<li>
<a href="[field:typelink/]">[field:typename/]</a>
{if $typeurl != ''}
<ul>
{dede:sonlist}
<li><a href="[field:typelink/]">[field:typename/]</a></li>
{/dede:sonlist}
</ul>
{/if}
</li>
{/dede:sonlist}
</ul>
{/dede:channel}
代码解释:
{dede:channel type='self' typeid='2'}: 先获取ID为2的“产品中心”栏目本身的信息。{dede:sonlist}: 这是一个神奇的标签,它会循环输出当前栏目的所有直接子栏目,它只能在channel或channelartlist标签内部使用。{if $typeurl != ''}: 这是一个判断。$typeurl是子栏目是否有子栏目的标志。$typeurl不为空,说明这个子栏目下面还有更下一级的栏目。- 内层的
{dede:sonlist}: 这是实现递归效果的关键,如果外层循环的某个子栏目本身也包含子栏目,我们就再次使用sonlist标签来循环输出它的子栏目,从而形成多级的树状结构。
注意: 这种嵌套 sonlist 的方法在 DedeCMS 5.7 版本中比较常用,但在更高版本或有特殊配置时可能需要调整,对于复杂的树状结构,有时也会通过自定义函数或PHP代码在 {dede:php}...{/dede:php} 标签内实现,但上述方法对于大多数场景已经足够。
| 需求 | 推荐方法 | 核心标签/函数 | 关键点 |
|---|---|---|---|
| 获取当前栏目的顶级栏目 | 使用 channel
| ||
| 获取当前栏目的直接父栏目 | 使用 channel
| ||
| 获取指定栏目的所有直接子栏目 | 使用 channelartlist + channel |
{dede:channelartlist}...{dede:channel type='son'}...{/dede:channel}{/dede:channelartlist} |
channelartlist 指定父栏目,channel 的 type='son' 获取子栏目。 |
| 获取指定栏目的所有子孙级栏目 | 使用 channel + sonlist (递归) |
{dede:channel}...{dede:sonlist}...{/dede:sonlist}{/dede:channel} |
sonlist 标签循环子栏目,可嵌套实现多级树状结构。 |
希望这些详细的解释和示例能帮助你顺利地在 DedeCMS 中实现父栏目和子栏目的调用!
