dede子栏目列表分页如何实现?

99ANYc3cd6
预计阅读时长 30 分钟
位置: 首页 DEDE建站 正文

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

dede子栏目列表分页
(图片来源网络,侵删)

下面我将从 原理、方法、代码示例、常见问题 四个方面来为你详细解答。


核心原理:理解 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} 会获取 手机、电脑、相机 这三个栏目下的所有文章,并混在一起进行分页。

dede子栏目列表分页
(图片来源网络,侵删)

分页的依据是 arcID (文章ID),而不是栏目ID,分页是跨子栏目的。


实现方法与代码示例

这里提供两种最常见的场景和对应的代码实现。

最常见的需求 - 显示所有子栏目的文章并分页

这是 DedeCMS 的默认行为,你只需要正确嵌套标签即可。

模板文件 (list_article.htm)

dede子栏目列表分页
(图片来源网络,侵删)

假设你要在列表页显示子栏目名称和文章列表。

{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参数 的经典实现方法。

思路:

  1. 在父栏目列表页,先显示所有子栏目的名称作为导航。
  2. 用户点击某个子栏目名称时,通过 JS 改变 URL,增加一个参数(如 cid=子栏目ID)。
  3. 页面根据这个 cid 参数,只调用对应子栏目的文章列表。
  4. {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 文件。

  1. 打开 include/arc.listview.class.php
  2. 找到 Query 方法(通常在文件末尾附近)。
  3. 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} 默认会生成一些 classpageinfo, 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 子栏目列表分页的问题!如果还有疑问,可以提出更具体的问题。

-- 展开阅读全文 --
头像
C语言如何判断输入的是否为数字?
« 上一篇 今天
织梦5.7免登陆接口如何实现安全免登录?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]