首页 / 开发文档 / 主题开发:从零做一套模板

主题开发:从零做一套模板

主题由哪些文件组成、模板名怎么被选中、一个最小可用主题的完整代码。

主题就是一堆模板文件

没有编译、没有构建:一个目录 + 里面的 .html 文件就是一套主题。 目录名就是主题标识,theme.json 是清单(可选,但强烈建议写)。

模板是怎么被找到的

templates/                 ← **唯一的主题根**,官方与第三方主题都在这里
├── default/               ← 官方主题:随系统升级更新
├── demo/                  ← 官方演示主题:随系统升级更新
└── mytheme/               ← 你的主题:**不在更新的白名单里,永不被动**

查找顺序:当前主题 → 它的父主题 → 再往上(最多 8 层)
都没找到 → 页面上会出现一行“模板缺失”注释,该页基本是空的
为什么第三方主题也放 templates/ 而不是另开一个 themes/: 谁受在线更新管辖,靠的是更新白名单里**逐个列出的目录名**(只有 default 与 demo), 不是靠目录位置。所以你放在 templates/mytheme/ 的东西, 系统升级时一个字节都不会被碰。
这条"往上找"的规则是子主题能只改一页的关键:你只放改动过的文件, 其余从父主题继承。父主题升级时,你改过的那几个文件不会被冲掉。

模板文件名与用途

文件什么时候用
index.html首页
list.html栏目页 /list/cid-1
detail.html内容详情页
page.html单页(后台建的"单页"栏目)
search.html站内搜索页
tag.html标签页 /tag/标签名
404.html找不着页面时
header.html / footer.html被上面这些页面 include 的公共部分

栏目还可以在后台单独指定模板文件,实现"这个栏目用另一套版式"。

最小可用主题

<!-- templates/mytheme/theme.json -->
{
  "name": "mytheme",
  "title": "我的主题",
  "version": "1.0.0",
  "parent": "default",
  "intro": "一句话说明风格"
}
<!-- templates/mytheme/index.html -->
{naicha:include file="header.html"}

<section class="section">
  <div class="container">
    <h1>{naicha:site name="title"}</h1>
    <p>{naicha:site name="description"}</p>

    <div class="grid3" style="margin-top:24px">
      {naicha:list num="6" order="sort desc"}
      <a class="card hover" href="{list.url}">
        <h3>{list.title}</h3>
        <p>{list.summary}</p>
        <div class="hint">{list.publish_time format="Y-m-d"}</div>
      </a>
      {/naicha:list}
    </div>
  </div>
</section>

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

parent 填了 default,所以 header.html、 footer.html、列表页、详情页都不必自己写 —— 它们从默认主题继承。 这就是最省力的起手式:只写你要改的那一页。

常用标签速查

标签作用
{naicha:site name="title"}站点设置里的任意一项(title / icp / copyright / contact_email …)
{naicha:navs type="top"}导航,循环里用 {navitem.name} / {navitem.url}
{naicha:list cid="1" num="10"}内容列表,循环里用 {list.title} / {list.url} / {list.summary} / {list.thumb}
{naicha:list name="别名"}按栏目别名取列表(栏目没写 cid 也没写 name 时才跟随当前栏目)
{naicha:detail}详情页上下文,里面用 {detail.title} / {detail.content html="1"}
{naicha:page page="{naicha:param name='page'}"}分页条
{naicha:tags}当前内容的标签
{naicha:include file="header.html"}引入另一个模板文件
{naicha:if var="x" eq="1"}…{naicha:else}…{/naicha:if}条件
{naicha:loop from="数组" as="i"}…{/naicha:loop}遍历控制器传进来的数组
{naicha:block name="片段名"}后台可编辑的页面片段

完整语法与全部标签见「标签手册」分组。写模板时记住一句: 模板层没有 SQL 能力,能取到什么完全由标签决定。

条件判断注意:empty / notempty 对数组不可靠 (数组会先被转成元素个数,空数组的 "0" 会被当成非空)。 判断数组非空用 gt="0",判断为空用 lt="1"。

样式怎么改

两条路:

  1. 小事:在模板里加 <style>,或用核心自带的样式类(.card / .btn / .grid3 / .badge / .section …)。
  2. 整套换皮:把自己的 CSS 放到站点 wwwroot/static/css/ 下,模板里用 {naicha:asset file='static/css/你的.css'} 引入。
主题目录不在网站根目录下,所以 templates/mytheme/static/… 这种写法是取不到的: {naicha:asset} 只认 wwwroot/ 下的文件。 想连样式一起分发,就把它放进 wwwroot/static/css/(或者干脆写进模板的 <style> 里)。
一定要用 {naicha:asset},别写死路径。服务器组件对静态文件不发缓存头, 浏览器会自己启发式缓存 —— 写死路径的话,你改了样式,用户可能几天都看不到新版。 {naicha:asset} 会把文件修改时间拼进 URL,改一次就自动换一次地址。

安装、切换与删除

  1. 把主题目录打包成 zip(顶层目录名 = 主题标识)
  2. 后台 外观 → 主题管理 上传安装
  3. 列表里点「切换到它」立即生效(会同时清掉模板缓存与整页缓存)
  4. 删主题:不能删当前正在用的,也不能删还有子主题依赖它的

手工装也行:把目录放到站点的 templates/<名字>/ 下即可,后台会直接列出来。

先动手试:脚手架

后台 应用商店 → 开发者脚手架 可以直接生成一份主题骨架(子主题或独立主题两种), 比自己新建目录、回忆清单字段快得多。

没找到答案? 可以在 联系我们 留言说明使用场景,我们会补充进文档。