这是一个非常常见的需求,但 DedeCMS 的默认机制有时会让人困惑,核心要点在于:子栏目列表的分页,默认是按照整个子栏目的所有文章进行分页,而不是按每个子栏目单独分页。

下面我将从 原理、方法、代码示例、常见问题 四个方面来为你详细解答。
核心原理:理解 DedeCMS 的列表分页机制
在 DedeCMS 中,当你调用一个栏目的子栏目时,通常使用 {dede:channelartlist} 或 {dede:channel} 标签,当你在这个标签内使用 {dede:list} 时,{dede:list} 的作用域是 当前父栏目下的所有子栏目的文章集合。
举个例子: 假设你有一个栏目 "产品中心" (ID=5),它下面有三个子栏目:
- 子栏目A:手机 (ID=10)
- 子栏目B:电脑 (ID=11)
- 子栏目C:相机 (ID=12)
当你访问 "产品中心" (ID=5) 的列表页时,{dede:list} 会获取 手机、电脑、相机 这三个栏目下的所有文章,并混在一起进行分页。

分页的依据是 arcID (文章ID),而不是栏目ID,分页是跨子栏目的。
实现方法与代码示例
这里提供两种最常见的场景和对应的代码实现。
最常见的需求 - 显示所有子栏目的文章并分页
这是 DedeCMS 的默认行为,你只需要正确嵌套标签即可。
模板文件 (list_article.htm)

假设你要在列表页显示子栏目名称和文章列表。
{dede:channelartlist typeid='父栏目ID'}
<h2>{dede:field name='typename'/}</h2>
<!-- 这里是子栏目名称 -->
<ul>
{dede:list pagesize='10'}
<li>
<a href="[field:arcurl/]">[field:title/]</a>
<span>[field:pubdate function="MyDate('Y-m-d',@me)"/]</span>
</li>
{/dede:list}
</ul>
<!-- ====== 以下是分页条代码 ====== -->
<div class="dede_pages">
<ul>
<li><span class="pageinfo">共 <strong>{dede:pagecount/}</strong> 页<strong>{dede:listtotal/}</strong> 条记录</span></li>
{dede:pagelist listsize='5' listitem='pre,next,end,option,info'}
</ul>
</div>
<!-- ====== 分页条代码结束 ====== -->
{/dede:channelartlist}
代码解释:
{dede:channelartlist typeid='父栏目ID'}: 循环父栏目下的所有子栏目。typeid填写你父栏目的ID。{dede:field name='typename'/}: 显示当前循环到的子栏目的名称。{dede:list pagesize='10'}: 在每个子栏目下,调用文章列表。pagesize='10': 非常重要! 这里设置每页显示的文章数量,分页会基于这个数量进行。
{dede:pagelist ...}: 这是生成分页导航的标签。listsize='5': 显示2个“上一页”和2个“下一页”的链接,共5个。listitem='pre,next,end,option,info': 定义分页条显示哪些部分。pre: 上一页next: 下一页end: 末页option: 跳转页(下拉框)info: 页面信息(如“共X页X条”)
后台设置
- 确保你的父栏目列表模板选择了
list_article.htm。 - 在后台 -> 系统 -> 系统基本参数 -> 核心设置中,检查
列表每页条数的默认值,确保它和你模板里pagesize的值一致或留空以使用默认值。
按每个子栏目单独分页(进阶需求)
这个需求稍微复杂一些,因为 DedeCMS 默认不支持,我们需要通过一些技巧来实现,比如使用 JS 或 PHP 来动态切换。
这里提供一个基于 JavaScript + URL参数 的经典实现方法。
思路:
- 在父栏目列表页,先显示所有子栏目的名称作为导航。
- 用户点击某个子栏目名称时,通过 JS 改变 URL,增加一个参数(如
cid=子栏目ID)。 - 页面根据这个
cid参数,只调用对应子栏目的文章列表。 {dede:list}的分页此时就只针对这一个子栏目的文章了。
模板文件 (list_article.htm)
<!-- 第1步:显示所有子栏目作为导航 -->
<div class="sub-channel-nav">
<a href="{dede:global.cfg_cmsurl/}/plus/list.php?tid={dede:field.id/}">全部</a>
{dede:channel type='son' noself='yes'}
<a href="javascript:;" onclick="filterByCid({dede:field.id/});">{dede:field.name/}</a>
{/dede:channel}
</div>
<!-- 第2步:定义一个隐藏的表单,用于提交 -->
<form id="filterForm" name="filterForm" method="get" action="">
<input type="hidden" name="tid" id="tid" value="{dede:field.id/}" />
<input type="hidden" name="cid" id="cid" value="" />
</form>
<!-- 第3步:文章列表容器 -->
<div id="article-list-container">
{dede:list pagesize='10'}
<li>
<a href="[field:arcurl/]">[field:title/]</a>
<span>[field:pubdate function="MyDate('Y-m-d',@me)"/]</span>
</li>
{/dede:list}
</div>
<!-- 第4步:分页条 -->
<div class="dede_pages">
<ul>
<li><span class="pageinfo">共 <strong>{dede:pagecount/}</strong> 页<strong>{dede:listtotal/}</strong> 条记录</span></li>
{dede:pagelist listsize='5' listitem='pre,next,end,option,info'}
</ul>
</div>
<!-- 第5步:JavaScript 代码 -->
<script type="text/javascript">
function filterByCid(cid) {
// 1. 设置表单中的 cid 值
document.getElementById('cid').value = cid;
// 2. 提交表单,页面会刷新并带上 cid 参数
document.getElementById('filterForm').submit();
}
// 页面加载后,检查 URL 中是否有 cid 参数
window.onload = function() {
var urlParams = new URLSearchParams(window.location.search);
var cid = urlParams.get('cid');
if (cid) {
// 如果有 cid 参数,说明需要筛选特定子栏目
// 我们需要修改 {dede:list} 的调用方式,这通常需要自定义SQL或者使用一个辅助标签
// 这里为了简化,我们假设你通过某种方式(如修改模板引擎)让 {dede:list} 能识别 cid 参数
// 在实际项目中,你可能需要修改 `arc.listview.class.php` 文件或在模板中使用 `{dede:sql}` 来实现
// 一个更简单但不够完美的替代方案是:直接跳转到子栏目的列表页
// window.location.href = '{dede:field.name runphp='yes'} $id = @me; @me = GetTopid($id); {/dede:field name runphp='yes'}' + '/' + cid + '.html';
// 这种方法会丢失父栏面的布局,不推荐。
// **推荐的解决方案是修改PHP代码**,这里只展示JS部分。
// 真正的实现需要在PHP端根据 $_GET['cid'] 来动态改变SQL查询的 `typeid` 条件。
}
};
</script>
PHP 代码修改(关键步骤)
上面的 JS 只是前端部分,真正的难点在于让 DedeCMS 的 {dede:list} 根据URL中的 cid 参数来筛选文章。
你需要修改 include/arc.listview.class.php 文件。
- 打开
include/arc.listview.class.php。 - 找到
Query方法(通常在文件末尾附近)。 - 在
Query方法中,找到生成typeid条件的 SQL 语句部分,增加对cid参数的判断。
修改前(大约在第550行左右):
// ... 其他代码 ...
$this->dsql->SetQuery("Select arc.*,tp.typedir,tp.typename,tp.corank,tp.isdefault,tp.defaultname,
tp.namerule,tp.namerule2,tp.ispart,tp.moresite,tp.siteurl,tp.sitepath
from `#@__archives` arc left join `#@__arctype` tp on arc.typeid=tp.id
where {$this->addSql} $ordersql limit $startrow,$this->PageSize");
// ... 其他代码 ...
修改后:
// ... 其他代码 ...
// 在原有代码基础上,增加对子栏目ID的筛选逻辑
$addSql = $this->addSql;
if (!empty($this->Channel->ChannelInfos['typeid']) && empty($cid)) {
// 如果是子栏目列表页,并且没有通过URL指定cid,则获取所有子栏目ID
$sontypeids = GetSonIds($this->Channel->ChannelInfos['typeid']);
if ($sontypeids != '') {
$addSql .= " AND arc.typeid IN($sontypeids) ";
}
} else {
// 如果URL中传来了cid参数,则只查询该cid下的文章
if (!empty($cid)) {
$addSql .= " AND arc.typeid = '$cid' ";
}
}
// 将修改后的 $addSql 应用到查询中
$this->dsql->SetQuery("Select arc.*,tp.typedir,tp.typename,tp.corank,tp.isdefault,tp.defaultname,tp.namerule,tp.namerule2,tp.ispart,tp.moresite,tp.siteurl,tp.sitepath
from `#@__archives` arc left join `#@__arctype` tp on arc.typeid=tp.id
where {$addSql} $ordersql limit $startrow,$this->PageSize");
// ... 其他代码 ...
如何让 $cid 变量可用?
你需要在 arc.listview.class.php 的构造函数 function __construct(...) 中,从 $_GET 全局变量中获取它。
在构造函数里添加:
// 在构造函数中添加这行 $this->cid = isset($_GET['cid']) ? intval($_GET['cid']) : 0;
在模板中调用 {dede:list} 的地方,需要确保父栏目ID被正确传递,并且你的 channelartlist 循环可能需要调整,这个方案相对复杂,通常用于有一定二次开发能力的用户。
常见问题与解决方案 (FAQ)
问题1:为什么我的分页只显示一页,或者点击下一页没反应?
- 原因1:
pagesize设置过大。 检查你的{dede:list pagesize='20'}和后台“系统基本参数”里的“列表每页条数”设置,如果文章总数少于这个值,自然就只有一页。 - 原因2:文章被归档或未审核。 确保你列表中的文章都是已审核且未被归档(
arcrank字段为0)的。 - 原因3:URL静态化规则冲突。 检查你的分页URL规则是否正确,规则可能是
list_{tid}_{page}.html,如果规则写错,下一页链接会失效。 - 原因4:PHP文件权限问题。 确保
/data目录和plus目录有正确的读写权限。
问题2:我想让每个子栏目有自己的独立分页,怎么做?
- 最佳方案: 直接访问子栏目的列表页,你的父栏目是
product(ID=5),子栏目是phone(ID=10),那么直接访问plus/list.php?tid=10,这个页面的分页就是完全独立的,这是 DedeCMS 的原生设计。 - 如果非要在一个页面里实现(如场景二): 那就必须采用上面提到的 JS + URL参数 + 修改PHP代码 的方法,这属于二次开发,有一定难度。
问题3:分页样式太丑,想自己改怎么办?
{dede:pagelist}默认会生成一些class,pageinfo,pagepre,pageno等。- 你可以直接在 CSS 文件中定义这些
class的样式来修改外观。 .dede_pages ul li { display: inline-block; margin: 0 5px; } .dede_pages a { display: inline-block; padding: 5px 10px; border: 1px solid #ddd; text-decoration: none; } .dede_pages a:hover { background-color: #f0f0f0; } .dede_pages .thisclass { background-color: #007bff; color: white; border-color: #007bff; }
希望这份详细的指南能帮助你彻底解决 DedeCMS 子栏目列表分页的问题!如果还有疑问,可以提出更具体的问题。
