- 推荐使用 CSS 下拉菜单(纯静态,最稳定)
- 使用 JavaScript 动态加载(适合内容频繁更新的栏目)
准备工作:修改顶部模板文件
无论使用哪种方法,首先都需要修改您的网站头部模板,通常是 /templets/default/header.htm 文件。

(图片来源网络,侵删)
- 登录DedeCMS后台:进入“模板” -> “默认模板管理”。
- 找到并编辑
header.htm:点击“修改”按钮。 - 定位导航代码:找到类似
{dede:channel type='top' row='8'}的标签,这就是您的一级导航代码。
CSS 下拉菜单(推荐)
这种方法利用 CSS 的 hover 伪类,当鼠标移动到一级菜单上时,自动显示对应的二级菜单,它不需要额外的 JS 文件,加载速度快,兼容性好。
第1步:修改 header.htm 文件
在 {dede:channel} 标签中,我们需要为每个一级菜单项增加一个 class,并让它能调用出它的子栏目,修改后的代码如下:
<div id="nav">
<ul>
{dede:channel type='top' row='8'}
<li>
<!--
* a 标签是显示一级菜单名称
* class="mainlevel" 用于CSS样式
* [field:typelink/] 是栏目链接
-->
<a href="[field:typelink/]" class="mainlevel">[field:typename/]</a>
<!--
* div id="sub_[field:id/]" 是存放二级菜单的容器
* style="display:none;" 默认隐藏
* class="subnav" 用于CSS样式
-->
<div id="sub_[field:id/]" class="subnav" style="display:none;">
<!--
* 在这里调用当前一级栏目下的所有子栏目
*typeid='[field:id/]' 指定当前父栏目ID
*row='10' 最多显示10个子栏目
-->
{dede:channel type='son' typeid='[field:id/]' row='10'}
<a href="[field:typelink/]">[field:typename/]</a>
{/dede:channel}
</div>
</li>
{/dede:channel}
<!-- 可以加上一个首页链接 -->
<li><a href="{dede:global.cfg_basehost/}" class="mainlevel">首页</a></li>
</ul>
</div>
代码解释:
{dede:channel type='top'}:循环输出顶级栏目。<a class="mainlevel">...</a>:一级菜单链接,我们给它一个mainlevel类以便添加样式。<div id="sub_[field:id/]" class="subnav" style="display:none;">:这是二级菜单的容器。id是唯一的(sub_1,sub_2...),class用于统一样式,style="display:none;"用于初始隐藏。{dede:channel type='son' typeid='[field:id/]'}:这是关键!它嵌套在一级菜单的li标签内,用于输出当前顶级栏目下的所有子栏目。typeid的值通过[field:id/]动态获取。
第2步:添加 CSS 样式
将以下 CSS 代码添加到您的模板 CSS 文件中(通常是 /templets/default/style/dedecms.css),或者在 header.htm 的 <head> 部分使用 <style> 标签嵌入。

(图片来源网络,侵删)
/* 导航容器样式 */
#nav {
height: 40px;
background-color: #333; /* 导航栏背景色 */
font-size: 14px;
}
#nav ul {
list-style: none;
margin: 0;
padding: 0;
}
#nav li {
float: left; /* 让菜单项横向排列 */
position: relative; /* 关键:为下拉菜单定位提供参考 */
}
#nav .mainlevel {
display: block;
padding: 0 15px;
line-height: 40px;
color: #fff;
text-decoration: none;
}
#nav .mainlevel:hover {
background-color: #555; /* 鼠标悬停时一级菜单的背景色 */
}
/* 二级菜单容器样式 */
#nav .subnav {
position: absolute; /* 关键:脱离文档流,进行绝对定位 */
top: 40px; /* 定位在一级菜单的下方 */
left: 0;
width: 200px; /* 设置二级菜单的宽度 */
background-color: #444; /* 二级菜单背景色 */
border: 1px solid #666;
z-index: 999; /* 确保菜单显示在最上层 */
}
/* 鼠标悬停在一级菜单上时,显示二级菜单 */
#nav li:hover .subnav {
display: block;
}
/* 二级菜单链接样式 */
#nav .subnav a {
display: block;
padding: 10px 15px;
color: #fff;
text-decoration: none;
border-bottom: 1px solid #555;
}
#nav .subnav a:hover {
background-color: #555; /* 鼠标悬停在二级菜单项上时的背景色 */
}
CSS 核心逻辑:
#nav li { position: relative; }:让每个一级菜单li成为二级菜单div的定位基准。#nav .subnav { position: absolute; top: 40px; }:让二级菜单相对于它的父级li进行绝对定位,并出现在其下方。#nav li:hover .subnav { display: block; }:这是实现下拉的核心,当鼠标悬停在li上时,其内部的.subnav元素(二级菜单)的display属性从none变为block,从而显示出来。
JavaScript 动态加载
如果你的二级栏目内容非常多,或者需要频繁更新,使用 CSS 可能会导致页面体积较大,这时可以用 JS 来动态加载二级菜单,实现“按需加载”,提高页面首屏加载速度。
第1步:修改 header.htm 文件
这里的结构比 CSS 方法更简单,二级菜单的容器初始是空的。
<div id="nav">
<ul>
{dede:channel type='top' row='8'}
<li>
<a href="[field:typelink/]" class="mainlevel nav-link" data-id="[field:id/]">[field:typename/]</a>
<!-- 二级菜单容器,初始为空 -->
<div class="subnav" id="subnav_[field:id/]" style="display:none;"></div>
</li>
{/dede:channel}
<li><a href="{dede:global.cfg_basehost/}" class="mainlevel">首页</a></li>
</ul>
</div>
关键改动:

(图片来源网络,侵删)
- 一级链接
<a>增加了class="nav-link"和data-id="[field:id/]"属性。data-id用于 JS 识别需要加载哪个栏目的子内容。 - 二级菜单
<div>的内容是空的,只保留了容器和id。
第2步:创建 JS 文件并调用
- 在您的模板目录下创建一个 JS 文件,
/templets/default/js/nav.js。 - 将以下代码复制到
nav.js文件中:
document.addEventListener('DOMContentLoaded', function() {
// 获取所有带有 nav-link 类的一级菜单链接
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
link.addEventListener('mouseenter', function() {
const parentId = this.getAttribute('data-id'); // 获取 data-id 的值
const subNavContainer = document.getElementById('subnav_' + parentId); // 找到对应的二级菜单容器
// 如果容器还没有内容,则通过AJAX加载
if (subNavContainer && subNavContainer.innerHTML === '') {
// 这里使用DedeCMS的arclist标签来模拟AJAX获取数据
// 实际项目中,你可能需要一个独立的PHP接口来返回JSON数据
// 这里为了方便,直接拼接HTML
let subItems = '';
// !!!重要提示:这里的URL需要根据你的网站结构调整
// 这只是一个示例,实际中不能直接在前端模板里写死PHP逻辑
// 更好的做法是创建一个 /include/get_subnav.php 文件,然后通过 fetch 调用
// 这里为了简化,我们假设你有一个办法能获取到数据
// 我们用一个假的循环来模拟
// {dede:channel type='son' typeid='[field:id/]' row='10'}
// subItems += `<a href="[field:typelink/]">[field:typename/]</a>`;
// {/dede:channel}
// 由于JS无法直接执行Dede标签,这里我们用一个占位符,你需要用其他方式填充它
subItems = '<a href="#">子栏目1</a><a href="#">子栏目2</a>'; // 替换为你的真实数据
subNavContainer.innerHTML = subItems;
}
// 显示二级菜单
if (subNavContainer) {
subNavContainer.style.display = 'block';
}
});
link.addEventListener('mouseleave', function() {
const subNavContainer = document.getElementById('subnav_' + this.getAttribute('data-id'));
if (subNavContainer) {
// 延迟隐藏,避免鼠标从一级菜单快速移动到二级菜单时菜单消失
setTimeout(() => {
subNavContainer.style.display = 'none';
}, 300);
}
});
});
});
JS 代码逻辑说明:
- 监听所有一级菜单的
mouseenter(鼠标进入)事件。 - 当鼠标进入时,通过
data-id找到对应的二级菜单容器。 - 检查容器是否为空:如果为空,说明是第一次加载,此时去获取子栏目的数据并填充进去。注意:JS 无法直接执行 Dede 标签,上面代码中的
subItems是一个占位符,在实际项目中,你需要:- 创建一个独立的 PHP 文件(
get_subnav.php),接收typeid参数,并用{dede:channel type='son'}查询数据,然后返回 HTML 片段或 JSON。 - 在 JS 中使用
fetch()或ajax()方法调用这个 PHP 文件,获取数据后再填充到容器中。
- 创建一个独立的 PHP 文件(
- 显示填充好内容的二级菜单。
- 监听
mouseleave(鼠标离开)事件,延迟一段时间后隐藏二级菜单,提升用户体验。
第3步:引入 JS 和 CSS
在 header.htm 的 </head> 标签之前,引入你创建的 JS 文件,并添加一些基本的 CSS 样式(和方法一中的 CSS 类似,但不需要 hover 规则)。
<!-- 在 head 部分添加 -->
<link rel="stylesheet" type="text/css" href="{dede:global.cfg_templets_skin/}/style/dedecms.css" />
<style>
/* 这里放方法二中提到的基本CSS样式,但去掉 #nav li:hover .subnav 的规则 */
#nav { height: 40px; background-color: #333; }
#nav ul { list-style: none; margin: 0; padding: 0; }
#nav li { float: left; position: relative; }
#nav .mainlevel { display: block; padding: 0 15px; line-height: 40px; color: #fff; text-decoration: none; }
#nav .mainlevel:hover { background-color: #555; }
#nav .subnav { position: absolute; top: 40px; left: 0; width: 200px; background-color: #444; border: 1px solid #666; z-index: 999; }
#nav .subnav a { display: block; padding: 10px 15px; color: #fff; text-decoration: none; border-bottom: 1px solid #555; }
#nav .subnav a:hover { background-color: #555; }
</style>
<script src="{dede:global.cfg_templets_skin/}/js/nav.js"></script>
总结与建议
| 特性 | 方法一 (CSS) | 方法二 (JS) |
|---|---|---|
| 实现难度 | 简单,只需修改模板和CSS | 中等,需要JS和少量后端知识 |
| 加载速度 | 快,无额外请求,CSS文件小 | 首屏快,二级菜单按需加载,适合复杂导航 |
| 维护性 | 高,纯静态,逻辑清晰 | 较低,JS逻辑稍复杂,需要处理AJAX |
| 兼容性 | 非常好,所有现代浏览器都支持 | 非常好,但需确保JS未禁用 |
对于 DedeCMS 5.7 这种老系统,我强烈推荐使用【方法一:CSS 下拉菜单】,它简单、稳定、高效,完全能满足大多数网站的需求,且不需要复杂的编程,只有在栏目层级非常深、二级内容极其庞大时,才考虑使用方法二来优化性能。
