主题开发:从零做一套模板
主题由哪些文件组成、模板名怎么被选中、一个最小可用主题的完整代码。
主题就是一堆模板文件
没有编译、没有构建:一个目录 + 里面的 .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"。
样式怎么改
两条路:
- 小事:在模板里加
<style>,或用核心自带的样式类(.card/.btn/.grid3/.badge/.section…)。 - 整套换皮:把自己的 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,改一次就自动换一次地址。
安装、切换与删除
- 把主题目录打包成 zip(顶层目录名 = 主题标识)
- 后台 外观 → 主题管理 上传安装
- 列表里点「切换到它」立即生效(会同时清掉模板缓存与整页缓存)
- 删主题:不能删当前正在用的,也不能删还有子主题依赖它的
手工装也行:把目录放到站点的 templates/<名字>/ 下即可,后台会直接列出来。
先动手试:脚手架
后台 应用商店 → 开发者脚手架 可以直接生成一份主题骨架(子主题或独立主题两种), 比自己新建目录、回忆清单字段快得多。