- 纯 CSS 下拉菜单 (推荐) - 无需修改 PHP,只需修改 CSS 和模板 HTML,最简单、最稳定。
- 基于 channelartlist 标签的下拉菜单 - 适用于需要调用自定义栏目并带有特定样式的场景。
准备工作:获取栏目数据
无论使用哪种方法,我们首先需要获取栏目的 HTML 结构,织梦的 channel 标签非常适合这个任务。
打开你的模板文件,通常是 templets/default/header.htm 或 templets/你的模板目录/header.htm。
在 <nav> 或 <div class="menu"> 等菜单容器内,使用以下代码来生成一个基础的、无样式的菜单列表:
{dede:channel type='top' row='8'}
<a href="[field:typeurl/]">[field:typename/]</a>
{/dede:channel}
这会生成类似这样的 HTML:
<a href="/">首页</a> <a href="/a/">栏目一</a> <a href="/b/">栏目二</a> <a href="/c/">栏目三</a> ...
我们的目标就是在这个基础上,为有子栏目的项添加下拉菜单。
纯 CSS 下拉菜单 (最推荐)
这种方法的核心思想是:用 CSS 来控制子菜单的显示和隐藏,完全不需要改动 PHP 逻辑。
第 1 步:修改模板 HTML 结构
我们需要修改 channel 标签,让它能够识别出哪些栏目有子栏目,并为其包裹一个 <li> 标签,子栏目则放在这个 <li> 的 <ul> 里。
在 header.htm 中,将菜单部分的代码替换为以下代码:
<ul id="nav">
{dede:channel type='top' row='8'}
<li>
<a href="[field:typeurl/]">[field:typename/]</a>
<!-- 这里是判断是否有子栏目的关键 -->
{dede:son typeid='[field:id/]'}
<ul class="sub-nav">
{dede:arclist typeid='[field:id]' row='10'}
<li><a href="[field:arcurl/]">[field:title/]</a></li>
{/dede:arclist}
</ul>
{/dede:son}
</li>
{/dede:channel}
</ul>
代码解释:
<ul id="nav">...</ul>:我们给菜单加了一个id方便 CSS 选择。{dede:channel type='top' row='8'}:调用顶级栏目。<li>...</li>:为每个顶级栏目项包裹一个<li>。<a href="...">...</a>:栏目链接。{dede:son typeid='[field:id/]'}...{/dede:son}:这是核心!这个标签会判断当前顶级栏目[field:id/]是否有子栏目,如果有,就会执行其中的内容。<ul class="sub-nav">...</ul>:如果存在子栏目,我们就创建一个子菜单列表ul,并给它一个 classsub-nav。{dede:arclist ...}:在子菜单ul内部,使用arclist标签来调用该顶级栏目下的文章列表作为子菜单项,你也可以继续使用{dede:channel}来调用二级栏目。
第 2 步:编写 CSS 样式
在你的 CSS 文件(通常是 templets/default/style/dedecms.css 或你的主样式文件)中,添加以下 CSS 代码:
/* 1. 重置和基础样式 */
#nav, #nav ul {
list-style: none;
margin: 0;
padding: 0;
background-color: #333; /* 菜单背景色 */
}
#nav > li {
float: left; /* 让菜单项横向排列 */
position: relative; /* 关键:为绝对定位的子菜单提供参照 */
}
#nav > li > a {
display: block;
padding: 10px 15px;
color: #fff;
text-decoration: none;
}
/* 2. 鼠标悬停效果 */
#nav > li > a:hover {
background-color: #555;
}
/* 3. 子菜单样式 - 默认隐藏 */
#nav ul.sub-nav {
position: absolute; /* 关键:将子菜单从文档流中脱离 */
top: 100%; /* 将子菜单放在父菜单项的下方 */
left: 0;
width: 200px; /* 子菜单宽度 */
background-color: #444;
display: none; /* 默认隐藏子菜单 */
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
/* 4. 当鼠标悬停在父级 li 上时,显示子菜单 */
#nav > li:hover > ul.sub-nav {
display: block; /* 鼠标悬停时显示 */
}
/* 5. 子菜单项的样式 */
#nav ul.sub-nav li {
width: 100%;
}
#nav ul.sub-nav li a {
display: block;
padding: 10px 15px;
color: #fff;
text-decoration: none;
border-bottom: 1px solid #555;
}
#nav ul.sub-nav li a:hover {
background-color: #555;
}
CSS 解释:
position: relative;在父级li上设置,这样里面的position: absolute;的子菜单才能相对于它定位。position: absolute;让子菜单ul脱离正常文档流,我们可以用top和left精确定位它的位置。top: 100%;确保子菜单出现在父级菜单项的下方。display: none;默认让子菜单不可见。#nav > li:hover > ul.sub-nav是选择器的精髓,它的意思是:当鼠标悬停 (hover) 在#nav的直接子级li上时,选择这个li的直接子级ulclass 是sub-nav的元素,并将其display设置为block,从而实现下拉效果。
完成以上两步,一个纯 CSS 的二级下拉菜单就做好了,这种方法性能好,易于维护,是前端开发的最佳实践。
基于 channelartlist 的下拉菜单
channelartlist 标签是专门用于制作复杂导航栏的,它可以直接循环顶级栏目,并在循环内嵌套调用其子栏目。
第 1 步:修改模板 HTML 结构
同样在 header.htm 中,将菜单部分替换为:
<ul id="nav">
{dede:channelartlist typeid='top' row='8'}
<li>
<a href="{dede:field name='typeurl'/}">{dede:field name='typename'/}</a>
<ul class="sub-nav">
{dede:channel type='son' noself='yes'}
<li><a href="[field:typeurl/]">[field:typename/]</a></li>
{/dede:channel}
</ul>
</li>
{/dede:channelartlist}
</ul>
代码解释:
{dede:channelartlist typeid='top' row='8'}:循环调用顶级栏目。<a href="{dede:field name='typeurl'/}">{dede:field name='typename'/}</a>:输出当前顶级栏目的链接和名称。{dede:channel type='son' noself='yes'}:在channelartlist的循环内部,这个标签会自动调用当前顶级栏目(即{dede:field name='id'})的子栏目。noself='yes'表示不显示栏目本身。- 这个方法生成的 HTML 结构和方法一完全一样,所以可以直接套用方法一的 CSS。
何时使用方法二?
- 当你的顶级栏目和二级栏目的样式、结构完全一致时,使用
channelartlist代码更简洁。 - 如果顶级栏目和二级栏目需要不同的样式(一级是文字,二级是带图标的卡片),
channelartlist的嵌套结构会更清晰。
总结与建议
| 特性 | 方法一 (纯 CSS + channel) | 方法二 (channelartlist) |
|---|---|---|
| 实现难度 | 简单,只需修改 HTML 和 CSS | 简单,模板标签稍复杂 |
| 灵活性 | 极高,可以完全自定义 HTML 结构 | 较高,但受限于标签本身的结构 |
| 性能 | 最佳,纯 CSS 效率最高 | 良好,但需要服务器解析嵌套标签 |
| 适用场景 | 绝大多数场景,特别是需要高度定制化设计的网站 | 快速构建标准化的多级导航栏 |
强烈推荐使用方法一,因为它更灵活、性能更好,并且是现代前端开发的通用标准,方法二可以作为备选,当你发现 channelartlist 的结构能完美匹配你的设计需求时再使用。
希望这个详细的教程能帮到你!如果在操作中遇到问题,可以检查一下你的 CSS 是否正确加载,以及浏览器开发者工具中 HTML 和 CSS 的状态。
