使用 {dede:channelartlist} 嵌套 {dede:type} (推荐)
这种方法最稳定、最符合DedeCMS的设计思想,也是官方文档中推荐的多级导航实现方式,它通过 channelartlist 指定顶级栏目,然后在内部循环中使用 type 标签来获取子栏目。

(图片来源网络,侵删)
准备工作
确保你的网站栏目结构已经搭建好,并且层级清晰,
- 一级栏目:首页
- 二级栏目:产品分类
- 三级栏目:电子产品
- 四级栏目:手机
- 四级栏目:电脑
- 四级栏目:相机
- 三级栏目:家居用品
- 四级栏目:家具
- 四级栏目:厨具
- 三级栏目:电子产品
修改模板文件
在你的网站头部模板文件 head.htm (或其他你存放导航的地方) 中,找到导航代码,将其替换为以下代码:
<div class="nav">
<ul>
<!-- 顶级栏目循环 (一级导航) -->
{dede:channelartlist typeid='0' row='8'}
<li>
<!-- 一级栏目名称 -->
<a href="{dede:field name='typeurl'/}">{dede:field name='typename'/}</a>
<!-- 判断是否有二级栏目,如果有则显示 -->
{dede:channel type='son' noself='yes'}
<div class="subnav">
<ul>
<!-- 二级栏目循环 -->
<li>
<!-- 二级栏目名称 -->
<a href="{dede:field name='typeurl'/}">{dede:field name='typename'/}</a>
<!-- 判断是否有三级栏目,如果有则显示 -->
{dede:channel type='son' noself='yes'}
<div class="subnav-sub">
<ul>
<!-- 三级栏目循环 -->
<li>
<!-- 三级栏目名称 -->
<a href="{dede:field name='typeurl'/}">{dede:field name='typename'/}</a>
<!-- 判断是否有四级栏目,如果有则显示 -->
{dede:channel type='son' noself='yes'}
<div class="subnav-sub-sub">
<ul>
<!-- 四级栏目循环 -->
<li><a href="{dede:field name='typeurl'/}">{dede:field name='typename'/}</a></li>
{/dede:channel}
</ul>
</div>
</li>
{/dede:channel}
</ul>
</div>
</li>
{/dede:channel}
</ul>
</div>
{/dede:channel}
</li>
{/dede:channelartlist}
<!-- 可以在这里添加一个“关于我们”等不属于顶级栏目的链接 -->
<li><a href="/aboutus.html">关于我们</a></li>
</ul>
</div>
代码解释
{dede:channelartlist typeid='0' row='8'}:typeid='0': 表示调用所有顶级栏目。row='8': 表示调用8个顶级栏目。- 这个标签循环输出一级导航。
{dede:field name='typeurl'/}和{dede:field name='typename'/}:- 这是
channelartlist标签内的底层字段,分别获取当前栏目的链接和名称。
- 这是
{dede:channel type='son' noself='yes'}:- 这是核心中的核心,它被嵌套在
channelartlist内部。 type='son': 表示调用当前栏目的直接子栏目,正是这个属性,使得我们可以无限向下嵌套。noself='yes': 表示不显示栏目本身,只显示子栏目。
- 这是核心中的核心,它被嵌套在
- 嵌套结构:代码通过层层嵌套
channelartlist->channel->channel->channel,实现了四级导航的显示,你可以根据你的实际栏目深度,增加或减少嵌套层数。
CSS 样式示例
为了让导航看起来更美观,你需要添加一些CSS样式来控制下拉菜单的显示。
/* 导航主容器 */
.nav ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
.nav > ul > li {
position: relative;
padding: 10px 15px;
}
.nav > ul > li > a {
text-decoration: none;
color: #333;
}
/* 二级菜单样式 */
.nav li .subnav {
display: none; /* 默认隐藏 */
position: absolute;
top: 100%;
left: 0;
background-color: #f9f9f9;
border: 1px solid #ddd;
min-width: 200px;
z-index: 1000;
}
.nav li:hover > .subnav {
display: block; /* 鼠标悬停时显示 */
}
/* 三级菜单样式 */
.subnav li .subnav-sub {
display: none;
position: absolute;
left: 100%;
top: 0;
}
.subnav li:hover > .subnav-sub {
display: block;
}
/* 四级菜单样式 */
.subnav-sub li .subnav-sub-sub {
display: none;
position: absolute;
left: 100%;
top: 0;
}
.subnav-sub li:hover > .subnav-sub-sub {
display: block;
}
/* 为各级菜单添加基本样式 */
.subnav ul, .subnav-sub ul, .subnav-sub-sub ul {
list-style: none;
padding: 0;
margin: 0;
}
.subnav ul li, .subnav-sub ul li, .subnav-sub-sub ul li {
width: 100%;
padding: 8px 15px;
}
.subnav a, .subnav-sub a, .subnav-sub-sub a {
text-decoration: none;
color: #555;
display: block;
}
使用 {ded:sql} 自定义查询 (高级)
如果你的栏目结构非常特殊,或者你对SQL比较熟悉,可以使用 ded:sql 标签直接从数据库中查询并构建导航,这种方法灵活性最高,但代码可读性稍差,且需要你对 dede_arctype 表结构有所了解。

(图片来源网络,侵删)
模板代码示例
<div class="nav">
<ul>
<!-- 获取顶级栏目 (topid=0) -->
{dede:sql sql="SELECT id,typename,typedir FROM `dede_arctype` WHERE reid=0 AND ishidden=0 ORDER BY sortrank"}
<li>
<a href='[field:typedir function='str_replace("{cmspath}", "", "@me")'/]'>[field:typename/]</a>
<!-- 获取二级栏目 (reid=顶级栏目id) -->
{dede:sql sql="SELECT id,typename,typedir FROM `dede_arctype` WHERE reid=[field:id/] AND ishidden=0 ORDER BY sortrank"}
<div class="subnav">
<ul>
<li>
<a href='[field:typedir function='str_replace("{cmspath}", "", "@me")'/]'>[field:typename/]</a>
<!-- 获取三级栏目 -->
{dede:sql sql="SELECT id,typename,typedir FROM `dede_arctype` WHERE reid=[field:id/] AND ishidden=0 ORDER BY sortrank"}
<div class="subnav-sub">
<ul>
<li>
<a href='[field:typedir function='str_replace("{cmspath}", "", "@me")'/]'>[field:typename/]</a>
<!-- 获取四级栏目 -->
{dede:sql sql="SELECT id,typename,typedir FROM `dede_arctype` WHERE reid=[field:id/] AND ishidden=0 ORDER BY sortrank"}
<div class="subnav-sub-sub">
<ul>
<li><a href='[field:typedir function='str_replace("{cmspath}", "", "@me")'/]'>[field:typename/]</a></li>
</ul>
</div>
{/dede:sql}
</li>
</ul>
</div>
{/dede:sql}
</li>
</ul>
</div>
{/dede:sql}
</li>
{/dede:sql}
</ul>
</div>
代码解释
dede:sql: 执行自定义的SQL查询语句。SELECT id,typename,typedir FROM dede_arctype WHERE reid=0:dede_arctype是DedeCMS存放栏目的表。reid=0表示顶级栏目。reid字段存储的是父栏目的ID。[field:id/]: 获取当前查询结果中的id字段,并将其传递给下一个嵌套的sql查询,作为reid的值,从而实现层级查询。function='str_replace("{cmspath}", "", "@me")': 这是一个非常重要的处理函数。typedir字段中默认包含{cmspath}这样的变量,需要将其替换掉才能得到正确的URL。
总结与建议
| 特性 | 方法一 (channelartlist + type) | 方法二 (dede:sql) |
|---|---|---|
| 易用性 | 高,符合DedeCMS标签体系,容易理解和修改。 | 低,需要SQL知识,代码复杂,不易维护。 |
| 稳定性 | 高,官方推荐,版本兼容性好。 | 中等,依赖于数据库表结构,未来版本升级可能有风险。 |
| 灵活性 | 中等,适合标准化的栏目层级。 | 极高,可以编写任意复杂的查询逻辑。 |
| 性能 | 良好,DedeCMS标签有缓存机制。 | 较差,每次页面加载都会执行SQL查询,无缓存。 |
强烈推荐使用 方法一,它足以满足绝大多数网站的四级导航需求,并且更安全、更易于维护,只有在遇到非常特殊的需求(需要跨栏目、按特定条件组合导航)时,才考虑使用方法二。
记得在后台的“模板” -> “默认模板管理”中,更新你的 head.htm 模块,并生成首页,这样修改才能生效。

(图片来源网络,侵删)
