下面我将为你提供一种最常用、最稳定且兼容性最好的实现方法,分为详细步骤和代码示例两部分,这种方法的核心是利用织梦的 channelartlist 标签来获取一级栏目,再在其循环内部嵌套 type 标签来获取当前一级栏目下的二级栏目。

使用 channelartlist + type 标签(推荐)
这种方法结构清晰,易于理解和维护,是织梦官方社区推荐的实现方式。
第一步:准备HTML结构
我们需要在模板文件中(通常是 head.htm 或 templets/default/header.htm)构建导航栏的HTML骨架,这个骨架清晰地表达了“一级栏目”和“二级栏目”的层级关系。
<!-- 导航栏开始 -->
<div class="nav">
<ul class="main-nav">
{dede:channelartlist typeid='top' row='8'}
<li class="main-item">
<!-- 一级栏目链接 -->
<a href="{dede:field name='typeurl'/}" class="main-link">
{dede:field name='typename'/}
</a>
<!-- 判断是否有子栏目,如果有则显示下拉框 -->
{dede:field name='ispart' runphp='yes'}
if(@me == 0) {
@me = '<div class="sub-nav"><ul class="sub-list">';
// 嵌套type标签获取二级栏目
{dede:type}
@me .= '<li><a href="[field:typelink/]">[field:typename/]</a></li>';
{/dede:type}
@me .= '</ul></div>';
} else {
@me = '';
}
{/dede:field}
</li>
{/dede:channelartlist}
<!-- 可以在这里添加一个首页链接 -->
<li class="main-item"><a href="{dede:global.cfg_basehost/}" class="main-link">首页</a></li>
</ul>
</div>
<!-- 导航栏结束 -->
代码解释:
-
{dede:channelartlist typeid='top' row='8'}:
(图片来源网络,侵删)typeid='top': 只调用顶级栏目。row='8': 限制显示8个一级栏目,你可以根据需要修改。- 这个标签会循环每一个顶级栏目。
-
<li class="main-item">: 这是每个一级栏目项的容器。 -
<a href="{dede:field name='typeurl'/}" ...>: 这是当前一级栏目的链接。 -
{dede:field name='typename'/}: 这是当前一级栏目的名称。 -
下拉菜单核心部分:
(图片来源网络,侵删){dede:field name='ispart' runphp='yes'}: 这是实现下拉菜单的关键。ispart字段判断当前栏目是否为“外部链接”。ispart == 0,说明它是一个普通栏目,可能包含子栏目;ispart == 1,说明它是一个外部链接,不应该显示下拉菜单。runphp='yes'允许我们在标签内使用PHP代码。if(@me == 0) { ... } else { ... }: 判断逻辑,如果不是外部链接,就生成下拉菜单的HTML代码;否则,生成空字符串。{dede:type} ... {/dede:type}: 在channelartlist循环内部,这个标签会获取当前循环项(即当前一级栏目)下的所有子栏目(二级栏目)。[field:typelink/]和[field:typename/]: 分别是二级栏目的链接和名称。
第二步:编写CSS样式
我们需要用CSS来美化这个导航栏,并实现鼠标悬停时下拉菜单显示的效果,将以下CSS代码添加到你的模板样式文件中(通常是 style/dedecms.css 或 templets/default/style.css)。
/* 导航栏基础样式 */
.nav {
background-color: #333; /* 导航栏背景色 */
height: 50px; /* 导航栏高度 */
font-family: "Microsoft YaHei", sans-serif;
}
.main-nav {
list-style: none;
margin: 0;
padding: 0;
display: flex; /* 使用Flexbox布局,让导航项水平排列 */
align-items: center;
height: 100%;
}
.main-item {
position: relative; /* 关键:为下拉菜单定位提供参考 */
margin-right: 20px;
}
.main-link {
color: #fff;
text-decoration: none;
display: block;
padding: 0 15px;
line-height: 50px; /* 行高等于高度,使文字垂直居中 */
font-size: 16px;
}
.main-link:hover {
background-color: #555; /* 鼠标悬停时的背景色 */
}
/* 下拉菜单样式 */
.sub-nav {
/* 默认隐藏下拉菜单 */
display: none;
/* 绝对定位,相对于其父元素 .main-item */
position: absolute;
top: 100%; /* 定位在一级栏目的正下方 */
left: 0;
background-color: #444;
min-width: 160px; /* 下拉菜单的宽度 */
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
z-index: 1000; /* 确保下拉菜单显示在内容之上 */
}
.sub-list {
list-style: none;
margin: 0;
padding: 0;
}
.sub-list li {
width: 100%;
}
.sub-list li a {
color: #fff;
text-decoration: none;
display: block;
padding: 12px 15px;
font-size: 14px;
}
.sub-list li a:hover {
background-color: #555;
}
/* 鼠标悬停在一级栏目上时,显示下拉菜单 */
.main-item:hover .sub-nav {
display: block;
}
CSS解释:
.main-item { position: relative; }: 这是最关键的一步,它将.main-item设置为定位上下文,这样里面的.sub-nav就可以使用position: absolute;相对于它进行定位。.sub-nav { display: none; }: 默认状态下,下拉菜单是隐藏的。.main-item:hover .sub-nav { display: block; }: 这是CSS的“后代选择器”,它的意思是:当鼠标悬停在.main-item上时,找到它的后代元素.sub-nav并将其display属性设置为block,从而显示出来,这就是纯CSS实现下拉效果的核心。
第三步:可选的JavaScript增强(用于移动端或更复杂的交互)
虽然上面的CSS已经可以实现基本的下拉效果,但有时我们可能需要用JavaScript来处理更复杂的情况,
- 在移动端,点击一级栏目展开/收起下拉菜单。
- 解决鼠标快速移动时下拉菜单闪烁的问题。
如果不需要,可以跳过此步。
// 将此代码放在页面底部的 <script> 标签内,或引入外部JS文件
document.addEventListener('DOMContentLoaded', function() {
const mainItems = document.querySelectorAll('.main-item');
mainItems.forEach(item => {
const link = item.querySelector('.main-link');
const subNav = item.querySelector('.sub-nav');
// 如果没有下拉菜单,则不执行任何操作
if (!subNav) return;
// 鼠标悬停事件(可选,可以用来优化PC端体验)
// item.addEventListener('mouseenter', () => {
// subNav.style.display = 'block';
// });
// item.addEventListener('mouseleave', () => {
// subNav.style.display = 'none';
// });
// 点击事件(主要用于移动端)
link.addEventListener('click', function(e) {
// 如果是PC端且没有子菜单,则正常跳转
if (window.innerWidth > 768 && !subNav) {
return;
}
// 阻止默认跳转行为
e.preventDefault();
// 切换下拉菜单的显示状态
if (subNav.style.display === 'block') {
subNav.style.display = 'none';
} else {
// 先关闭其他所有打开的下拉菜单
document.querySelectorAll('.sub-nav').forEach(nav => {
nav.style.display = 'none';
});
// 再打开当前的下拉菜单
subNav.style.display = 'block';
}
});
});
});
使用 arclist 标签(备选方案)
如果你的网站结构比较特殊,或者不想用 channelartlist,也可以用 arclist 来实现,这种方法稍微复杂一点,需要手动处理循环。
<div class="nav">
<ul class="main-nav">
<!-- 先循环顶级栏目 -->
{dede:channel type='top' row='8'}
<li class="main-item">
<a href="[field:typeurl/]" class="main-link">[field:typename/]</a>
<!-- 在循环内部,用arclist获取当前栏目的子栏目 -->
{dede:arclist typeid='[field:id]' row='100'}
<!-- arclist只输出一个循环项,我们用它来构建下拉菜单 -->
<div class="sub-nav">
<ul class="sub-list">
<!-- 再次调用channel标签来获取所有子栏目 -->
{dede:channel typeid='[field:id]'}
<li><a href="[field:typeurl/]">[field:typename/]</a></li>
{/dede:channel}
</ul>
</div>
{/dede:arclist}
</li>
{/dede:channel}
</ul>
</div>
注意:这种方法嵌套了三层标签,效率上可能略低于 channelartlist,且逻辑稍显绕。强烈推荐使用第一种方法。
| 步骤 | 核心操作 | 关键代码/标签 |
|---|---|---|
| HTML结构 | 搭建导航栏骨架,使用channelartlist循环一级栏目,内部用type循环二级栏目。 |
{dede:channelartlist}{dede:field name='ispart' runphp='yes'}{dede:type} |
| CSS样式 | 美化外观,实现鼠标悬停时下拉菜单的显示效果。 | .main-item { position: relative; }.sub-nav { display: none; }.main-item:hover .sub-nav { display: block; } |
| JavaScript | (可选) 增强交互,如处理移动端点击事件。 | addEventListener('click', ...) |
按照以上步骤操作,你就可以在织梦CMS中成功实现一个功能完善、外观漂亮的导航下拉菜单了,如果在实际操作中遇到问题,请检查你的栏目设置(特别是是否为外部链接)以及CSS和JS文件是否正确引入。
