首页 / 开发文档 / 内容列表:{naicha:list}

内容列表:{naicha:list}

列表页的主角。全部参数、排序键、循环里能用的字段,以及一份可以直接抄的完整列表页。

适用范围:列表页;首页、详情页侧栏、任意需要「取一批内容」的地方。

基本写法

{naicha:list cid="3" num="10" page="{naicha:param name='page'}" order="publish desc"}
  <a href="{list.url}">{list.title}</a>
{/naicha:list}

全部参数

cid当前栏目;栏目 id
name—;栏目别名(推荐,比写死 id 好)。⚠️ 只有 cid 和 name 都没写时才继承当前栏目
num10;每页条数(上限 100)
page当前页;页码,通常写 {naicha:param name='page'}
ordersort desc;排序键,见下
keyword搜索词;关键词搜索
model—;只取某个内容模型的内容(如 media)
top—;只看置顶(1)
tag / tags / tagmode—;按标签筛;tags="a,b" 多标签,tagmode="and"(默认)/ or
field op fvalue—;按自定义字段筛(op 是比较方式)
withsub / sub—;连子栏目一起取
media—;顺带取图集(列表页每行多一个 {list.gallery})
filters—;filters="1" 表示这个列表接受 URL 上的筛选(排序/时间/标签)。侧栏那种局部列表不要开
kwscope站点设置;搜索范围(标题摘要 / 含正文)

排序键(写错的会静默回落到 sort desc)

sort desc sort asc publish desc publish asc hits desc id desc id asc relevance(只在带 keyword 时有意义)

⚠️ 写错不报错,页面照常渲染,只是顺序不对。看着「正常」而顺序怪,先来这一行对一下。

循环体里能用的字段(一条不漏)

下面这些都写 {list.字段名}。列表查询取的是内容表整行,所以表里有的列模板里都能取, 包括平时用不到的。

基本

{list.id}内容 id。拼自定义链接、调 {naicha:rel} / {naicha:gallery} 都要它
{list.cid}所属栏目 id
{list.model}内容模型名(article / media / 自定义的)
{list.title}标题
{list.alias}别名(拼固定地址用;没填就是空串)
{list.url}详情页地址(已带语言前缀,别再自己拼)
{list.summary}摘要;没填过时引擎会自动从正文截前 120 字
{list.content}正文 HTML。⚠️ 输出必须写 html="1",否则会被转义成源码显示出来

时间与状态

{list.publish_time}发布时间。配 format="Y-m-d" 用
{list.is_new}1/0,7 天内发布的。判断要写 eq="1"
{list.hits}浏览量
{list.top}是否置顶(1/0)
{list.sort}后台填的排序值
{list.status}状态(published 已发布 / 其它为待审等)
{list.author_id}作者的用户 id(想显示名字得自己按 id 映射)
{list.lang}属于哪个语言(空串 = 不限语言)
{list.created_at} {list.updated_at}入库时间 / 最后修改时间(与发布时间不是一回事)

图片

{list.thumb}封面图的相对路径。⚠️ 别直接塞进 src,见下面的提示
{list.thumb_url}封面图可直接用的地址(引擎算好的)。没图时是空串
{list.has_thumb}1/0,有没有封面图 —— 套一层 {naicha:if} 省得渲染一个空 <img>
{list.gallery}图集数组,只有写了 media="1" 才有;元素里有 path / url / alt
{list.gallery_count}图集里有几张(做「共 N 图」角标)
{list.has_gallery}1/0,有没有图集

⚠️ {list.thumb} 存的是相对路径(uploads/2026xx/a.png)。 在 /list/cid-3 这类多层地址下直接写进 src,浏览器会当成 /list/uploads/…,图全裂。 一律用 {list.thumb_url} —— 它还顺带处理了多语言前缀。

自定义字段与门槛

{list.扩展字段名}直接写字段名就行。引擎在正式列里找不到同名时,会自动去扩展字段里找 —— 所以 {list.media_type} 与 {list.ext.media_type} 完全等价,前者更好写
{list.need_login}1 = 这篇仅登录可见
{list.need_level}大于 0 = 需要该等级及以上
{list.detail_template}这篇指定用哪套详情版式(空 = 跟栏目或主题默认)
{list.files}附件(下载型内容用)
{list.reject_reason}被驳回的原因(后台审核流程用,前台一般是空串)
取不到的值一律是空串,不报错。 所以「页面上少了一块」八成是名字写错了,而不是引擎坏了 —— 先照上面的表对一遍拼写,再去看「嵌套与失败模式」那一篇。

一份可以直接抄的列表页

<!-- [templates/default/list.html] -->
{naicha:include file="header.html"}

<div class="page-head">
  <h1>{sort.name}</h1>
  <p>{sort.intro}</p>
</div>

<div class="container">
  <!-- filters="1" 让这个列表响应地址栏上的筛选(排序 / 年份 / 标签)-->
  {naicha:filters show="sort,year,tag"}

  <div class="grid c3">
    {naicha:list cid="{naicha:param name='cid'}" num="12"
                 page="{naicha:param name='page'}" filters="1" order="publish desc"}
      <a class="card" href="{list.url}">
        {naicha:if var="list.has_thumb" eq="1"}
        <img src="{list.thumb_url}" alt="{list.title}">
        {/naicha:if}
        <h3>{list.title}</h3>
        <p>{list.summary excerpt="60"}</p>
        <span>{list.publish_time format="Y-m-d"} · 浏览 {list.hits}</span>
        {naicha:if var="list.is_new" eq="1"}<span class="badge">最新</span>{/naicha:if}
      </a>
    {/naicha:list}
  </div>

  <!-- 空结果要说一句人话,而不是留一片空白 -->
  {naicha:if var="listTotal" eq="0"}
    <div class="empty">
      <p>这个栏目还没有内容。{naicha:if var="keyword" notempty="1"}换个关键词试试。{/naicha:if}</p>
    </div>
  {/naicha:if}

  {naicha:page}
</div>

{naicha:include file="footer.html"}

同一栏目里放不同版式

<!-- [列表] 视频栏目用播放角标,其它用普通卡片 -->
{naicha:list cid="{naicha:param name='cid'}" num="12" media="1"}
  {naicha:if var="list.media_type" eq="video"}
    <span class="badge play">▶ {list.duration}</span>
  {naicha:elseif var="list.media_type" eq="audio"}
    <span class="badge audio">♪ {list.duration}</span>
  {naicha:else}
    <span class="badge">图文</span>
  {/naicha:if}
{/naicha:list}

{list.media_type} 是内容模型的扩展字段 —— 引擎在同名列找不到时会自动去 ext 里找,所以不用写 {list.ext.media_type}。

点赞 / 反对(后补的字段)

{list.likes}点赞数
{list.oppose}反对数
{list.likeslink}点赞地址,直接当 href 用即可(点一次算一票,重复点不叠加)
{list.opposelink}反对地址
<!-- 点赞 / 反对。链接直接点就行,不用写 JS -->
<a class="like" href="{list.likeslink}">赞 <b>{list.likes}</b></a>
<a class="oppose" href="{list.opposelink}">踩 <b>{list.oppose}</b></a>

<!-- 想点完不跳页,加一个 fetch 即可(接口对 ajax=1 返回 JSON)-->
<script>
document.querySelectorAll('.like,.oppose').forEach(function (a) {
  a.addEventListener('click', function (ev) {
    ev.preventDefault();
    fetch(a.href + '&ajax=1').then(function (r) { return r.json(); }).then(function (d) {
      if (d.ok) { a.querySelector('b').textContent = d.likes || d.oppose; }
    });
  });
});
</script>

行所属栏目与作者(后补的字段)

{list.sortname} {list.sorturl}这一行属于哪个栏目 —— 混排列表(多个栏目一起列)要用
{list.author}作者名(取昵称,没填取用户名;没设作者时是空串)
没找到答案? 可以在 联系我们 留言说明使用场景,我们会补充进文档。