从零做一套主题

复制 default 改个名,把首页、栏目页、详情页、单页、搜索页五个模板写出来,最后换上去。全程可复制。

约 28 分钟 模板 代码块右上角可一键复制
本页目录(28 分钟读完)

这一章只做一件事:照着抄,做出一套能用的自己的模板。

语法不懂 → 看 模板开发入门。 标签记不住 → 看 模板标签速查。 页面报错 → 看 排错手册。

怎么准备主题目录#

作用:先有一个自己的主题文件夹,改坏了也不影响线上。

步骤:

  1. 进入项目里的 view 目录
  2. 复制 default 整个文件夹
  3. 把副本改名成 mysite
Shell
cd view
cp -r default mysite

效果:多出 view/mysite/,结构和 default 一样。

文件是什么页面
layout.html全站骨架
common/header.html页头导航
common/footer.html页脚
common/pager.html分页条
index/index.html首页
index/node.html栏目页
index/article.html详情页
index/page.html单页
index/search.html搜索页
static/css/style.css样式

先切过去再改:

  1. 后台 → 系统设置 → 基础设置
  2. 「前台模板」选 mysite
  3. 点「保存」
  4. 跑 php aucms cache:clear
文本
改一点,刷新看一点。
改坏了就切回 default,站点不受影响。

打不开? → 看 排错手册

怎么写布局#

作用:定下每个页面的 HTML 骨架。

步骤:

  1. 打开 view/mysite/layout.html
  2. 整个文件换成下面这份
  3. 保存
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{if !empty($seo.title)}{$seo.title}{else}{$site.name}{/if}</title>
{if !empty($seo.keywords)}<meta name="keywords" content="{$seo.keywords}">{/if}
{if !empty($seo.description)}<meta name="description" content="{$seo.description}">{/if}
<link rel="stylesheet" href="{$asset_css}">
</head>
<body>
{include common/header}

<main class="wrap">
  {content}
</main>

{include common/footer}
<script src="{$asset_js}" defer></script>
</body>
</html>

效果:每个页面都套这个骨架,标题自动带 SEO。

文本
样式地址必须写 {$asset_css},不要写死路径。
写死就没有版本号,改了样式用户看不到。

打不开? → 看 排错手册

怎么写页头#

作用:显示站点名、导航、搜索框。

步骤:

  1. 打开 view/mysite/common/header.html
  2. 整个文件换成下面这份
  3. 保存
HTML
<header class="hd">
  <div class="wrap hd__in">
    <a class="hd__brand" href="/">
      {if !empty($site.logo)}
      <img src="{$site.logo}" alt="{$site.name}" height="32">
      {else}
      {$site.name}
      {/if}
    </a>

    <nav class="hd__nav">
      <a href="/">首页</a>
      {loop $primary_nav as $nav}
      <a href="{$nav.url}"{if $nav.target == '_blank'} target="_blank" rel="noopener"{/if}>{$nav.name}</a>
      {/loop}
    </nav>

    <form class="hd__search" action="/search" method="get">
      <input type="search" name="q" value="{$keyword}" placeholder="搜索">
      <button type="submit">搜</button>
    </form>
  </div>
</header>

效果:页头按「导航组」列菜单(可含外链与二级)。在后台「导航管理」里配,见 导航组。

打不开? → 看 排错手册

怎么写页脚#

作用:显示版权、备案号、统计代码。

步骤:

  1. 打开 view/mysite/common/footer.html
  2. 整个文件换成下面这份
  3. 保存
HTML
<footer class="ft">
  <div class="wrap">
    <p>{$site.copyright|default=''}</p>
    <p class="ft__links">
      {loop $nodes as $nav}
      <a href="/list/{$nav.slug}">{$nav.name}</a>
      {/loop}
    </p>
    {if !empty($site.icp)}
    <p><a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener nofollow">{$site.icp}</a></p>
    {/if}
  </div>
  {if !empty($site.statistics)}{$site.statistics|raw}{/if}
</footer>

效果:后台填的版权、备案、统计代码自动出现。

文本
统计代码必须加 |raw。
不加会显示成一串 &lt;script&gt; 文字,统计收不到数据。

打不开? → 看 排错手册

怎么写首页#

作用:显示头条、最新列表、热门、标签。

步骤:

  1. 打开 view/mysite/index/index.html
  2. 整个文件换成下面这份
  3. 保存

首页数据已经由系统取好,不用自己查库。

变量是什么
$lead头条(最新一条)
$feed其余内容
$hot热门
$tags标签
HTML
{layout layout}

<section class="hero">
  <h1>{$site.title|default=$site.name}</h1>
  <p>{$site.description|default=''}</p>
</section>

<div class="cols">
  <div class="cols__main">
    {if !empty($lead)}
    <article class="lead">
      {if !empty($lead.thumb)}
      <a class="lead__img" href="{$lead.url}">
        <img src="{$lead.thumb|thumb=720,420}" alt="{$lead.title}">
      </a>
      {/if}
      <div class="lead__body">
        <h2><a href="{$lead.url}">{$lead.title}</a></h2>
        <p>{$lead.description|limit=140}</p>
        <time>{$lead.created_at|date=Y-m-d}</time>
      </div>
    </article>
    {/if}

    <div class="feed">
      {loop $feed as $item}
      <article class="item">
        <h3><a href="{$item.url}">{$item.title}</a></h3>
        <p>{$item.description|limit=80}</p>
        <div class="item__meta">
          <time>{$item.created_at|date=Y-m-d}</time>
          <span>{$item.views|default=0} 阅读</span>
        </div>
      </article>
      {/loop}
    </div>

    {if empty($lead) && empty($feed)}
    <div class="empty">
      <p>站点还没有内容。</p>
      <p>去后台发布第一篇吧。</p>
    </div>
    {/if}
  </div>

  <aside class="cols__side">
    <h3 class="side__title">热门</h3>
    <ol class="side__list">
      {loop $hot as $item}
      <li><a href="{$item.url}">{$item.title|limit=26}</a></li>
      {/loop}
    </ol>

    {if !empty($tags)}
    <h3 class="side__title">标签</h3>
    <div class="tags">
      {loop $tags as $t}
      <a href="/tag/{$t.name}">#{$t.name}</a>
      {/loop}
    </div>
    {/if}
  </aside>
</div>

效果:前台打开 /,能看到头条和列表。

打不开? → 看 排错手册

怎么写栏目页#

作用:显示一个栏目的内容列表。

步骤:

  1. 打开 view/mysite/index/node.html
  2. 整个文件换成下面这份
  3. 保存
HTML
{layout layout}

<header class="page-hd">
  <nav class="crumb">
    <a href="/">首页</a> / <span>{$node.name}</span>
  </nav>
  <h1>{if !empty($node.title)}{$node.title}{else}{$node.name}{/if}</h1>
  {if !empty($node.description)}<p>{$node.description}</p>{/if}
</header>

<div class="feed">
  {loop $list as $item}
  <article class="item">
    {if !empty($item.thumb)}
    <a class="item__img" href="{$item.url}">
      <img src="{$item.thumb|thumb=240,160}" alt="{$item.title}" loading="lazy">
    </a>
    {/if}
    <div class="item__body">
      <h3><a href="{$item.url}">{$item.title}</a></h3>
      <p>{$item.description|limit=100}</p>
      <div class="item__meta">
        <time>{$item.created_at|date=Y-m-d}</time>
        <span>{$item.views|default=0} 阅读</span>
      </div>
    </div>
  </article>
  {/loop}
</div>

{if empty($list)}
<div class="empty">这个栏目还没有内容。</div>
{/if}

{include common/pager}

效果:打开 /list/栏目别名,能看到该栏目的文章。

打不开? → 看 排错手册

怎么写详情页#

作用:显示一篇文章的正文。

步骤:

  1. 打开 view/mysite/index/article.html
  2. 整个文件换成下面这份
  3. 保存
HTML
{layout layout}

<article class="post">
  <nav class="crumb">
    <a href="/">首页</a>
    {if !empty($node)} / <a href="/list/{$node.slug}">{$node.name}</a>{/if}
  </nav>

  <h1 class="post__title">{$article.title}</h1>

  <div class="post__meta">
    <time>{$article.created_at|date=Y-m-d H:i}</time>
    <span>{$article.views|default=0} 阅读</span>
  </div>

  {if !empty($article.thumb)}
  <img class="post__cover" src="{$article.thumb|thumb=960,0}" alt="{$article.title}">
  {/if}

  <div class="post__body">{$article.content|raw}</div>

  {if !empty($article.tags_links)}
  <div class="tags">
    {loop $article.tags_links as $tl}
    <a href="{$tl.url}">#{$tl.name}</a>
    {/loop}
  </div>
  {/if}
</article>

<div class="post-nav">
  {if !empty($prev)}
  <a href="{$prev.url}"><span>上一篇</span>{$prev.title|limit=24}</a>
  {/if}
  {if !empty($next)}
  <a href="{$next.url}"><span>下一篇</span>{$next.title|limit=24}</a>
  {/if}
</div>

{if !empty($related)}
<section class="related">
  <h2>相关阅读</h2>
  <ul>
    {loop $related as $item}
    <li><a href="{$item.url}">{$item.title|limit=32}</a></li>
    {/loop}
  </ul>
</section>
{/if}

效果:从栏目页点标题,能看到正文、上下篇、相关阅读。

文本
正文必须写 {$article.content|raw}。
不加 raw 会显示一堆 &lt;p&gt; 标签原文。

打不开? → 看 排错手册

怎么写单页#

作用:显示「关于我们」这类固定页。

步骤:

  1. 打开 view/mysite/index/page.html
  2. 整个文件换成下面这份
  3. 保存
HTML
{layout layout}
<article class="post">
  <h1 class="post__title">{$article.title}</h1>
  <div class="post__body">{$article.content|raw}</div>
</article>

效果:打开 /page/别名,显示标题和正文。

打不开? → 看 排错手册

怎么写搜索页#

作用:显示搜索结果。

步骤:

  1. 打开 view/mysite/index/search.html
  2. 整个文件换成下面这份
  3. 保存
HTML
{layout layout}

<header class="page-hd">
  <h1>搜索{if !empty($keyword)}:{$keyword}{/if}</h1>
  <form action="/search" method="get">
    <input type="search" name="q" value="{$keyword}" placeholder="输入关键词">
    <button type="submit">搜索</button>
  </form>
</header>

{loop $list as $item}
<article class="item">
  <h3><a href="{$item.url}">{$item.title}</a></h3>
  <p>{$item.description|limit=100}</p>
</article>
{/loop}

{if empty($list)}
<div class="empty">没有找到相关内容,换个词试试。</div>
{/if}

{include common/pager}

效果:打开 /search?q=关键词,能看到结果列表。

打不开? → 看 排错手册

怎么写样式#

作用:决定站点长什么样。

步骤:

  1. 打开 view/mysite/static/css/style.css
  2. 先换成下面这份最小可用样式
  3. 保存
  4. 浏览器强制刷新(Ctrl+F5)
CSS
:root{
  --ink:#1b2430; --mute:#6b7684; --line:#e6eaf0;
  --bg:#fff; --soft:#f7f9fc; --brand:#2563eb;
  --wrap:1140px; --radius:10px;
}
*{box-sizing:border-box}
body{margin:0;font:16px/1.75 -apple-system,"PingFang SC","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--bg)}
a{color:inherit;text-decoration:none}
a:hover{color:var(--brand)}
img{max-width:100%;display:block}

.wrap{width:100%;max-width:var(--wrap);margin:0 auto;padding:0 18px}
.hd{border-bottom:1px solid var(--line);position:sticky;top:0;background:#fff;z-index:20}
.hd__in{display:flex;align-items:center;gap:24px;height:62px}
.hd__brand{font-weight:700;font-size:18px;color:var(--brand)}
.hd__nav{display:flex;gap:18px;flex:1;font-size:15px}
.hd__search{display:flex;gap:6px}
.hd__search input{height:34px;padding:0 10px;border:1px solid var(--line);border-radius:8px;outline:none}
.hd__search input:focus{border-color:var(--brand)}

.cols{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:34px;padding:28px 0 60px}
.lead{display:grid;grid-template-columns:1.15fr 1fr;gap:22px;margin-bottom:28px;padding-bottom:26px;border-bottom:1px solid var(--line)}
.lead__img img{border-radius:var(--radius);aspect-ratio:16/9;object-fit:cover}
.lead__body h2{margin:0 0 10px;font-size:24px;line-height:1.35}
.lead__body p{color:var(--mute);margin:0 0 10px}
.item{display:flex;gap:16px;padding:16px 0;border-bottom:1px solid var(--line)}
.item__body h3{margin:0 0 6px;font-size:17px;font-weight:600}
.item__body p{margin:0 0 8px;color:var(--mute);font-size:14.5px}
.item__meta{font-size:12.5px;color:#98a2b3;display:flex;gap:12px}
.item__img img{width:200px;height:130px;object-fit:cover;border-radius:8px}

.post{max-width:820px;margin:0 auto;padding:28px 0}
.post__title{font-size:30px;line-height:1.35;margin:12px 0 12px}
.post__meta{color:var(--mute);font-size:13px;display:flex;gap:14px;margin-bottom:22px}
.post__cover{border-radius:var(--radius);margin:0 0 22px}
.post__body{font-size:16.5px;line-height:1.9}
.post__body p{margin:16px 0}
.post__body h2{margin:36px 0 12px;font-size:21px}
.post__body img{border-radius:8px;margin:16px 0}
.post__body pre{background:#0f1724;color:#dbe4f0;padding:14px;border-radius:8px;overflow:auto}
.post__body table{width:100%;border-collapse:collapse}
.post__body th,.post__body td{border:1px solid var(--line);padding:8px 10px}

.tags{display:flex;flex-wrap:wrap;gap:8px;margin:20px 0}
.tags a{font-size:13px;background:var(--soft);padding:3px 10px;border-radius:999px;color:var(--mute)}
.tags a:hover{background:#eaf0ff;color:var(--brand)}

.cols__side .side__list{padding-left:18px;margin:0 0 28px;font-size:14.5px}
.cols__side .side__list li{margin:8px 0;color:var(--mute)}
.side__title{font-size:14px;letter-spacing:.06em;text-transform:uppercase;color:#98a2b3;margin:0 0 10px}

.crumb{font-size:13px;color:var(--mute);margin-bottom:10px}
.page-hd{padding:26px 0 10px;border-bottom:1px solid var(--line)}
.page-hd h1{font-size:26px;margin:6px 0 8px}
.empty{padding:50px 0;text-align:center;color:var(--mute)}
.ft{border-top:1px solid var(--line);padding:26px 0;text-align:center;color:var(--mute);font-size:13px}
.ft__links{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}

@media(max-width:880px){
  .cols{grid-template-columns:1fr}
  .lead{grid-template-columns:1fr}
  .hd__nav{display:none}
  .item__img img{width:120px;height:82px}
}

效果:站点有导航、列表、正文排版,手机上不横向滚动。

改配色只改最上面几行:

变量改什么
--brand主色(链接、按钮)
--ink正文颜色
--bg背景色
--wrap内容宽度

打不开? → 看 排错手册

怎么换上去看效果#

作用:确认每个页面都正常。

步骤:

  1. 后台 → 系统设置 → 基础设置
  2. 「前台模板」选 mysite
  3. 点「保存」
  4. 跑命令清缓存
Shell
php aucms cache:clear
  1. 前台按这个顺序点一遍
顺序打开哪里该看到什么
1/首页有头条和列表
2/list/你的栏目栏目列表
3从栏目点进一篇文章详情正文
4/page/about(如果建了)单页
5/search?q=随便搜索结果
6/abc-def-xyz404 页
7浏览器切到手机宽度不横向滚动

每个页面问自己三句:有样式吗?有内容吗?控制台报错吗?

打不开? → 看 排错手册

怎么让不同栏目用不同模板#

作用:「产品」用网格、「新闻」用列表,不用做两套主题。

步骤:

  1. 新建 view/mysite/node/grid.html,写网格版列表
  2. 后台 → 内容 → 栏目管理
  3. 点开「产品中心」
  4. 「列表模板」填 grid
  5. 点「保存」

效果:产品栏目用 grid.html,其它栏目仍用 index/node.html。

详情页同理:

  1. 新建 view/mysite/article/video.html
  2. 栏目编辑里「详情模板」填 video

打不开? → 看 排错手册

上线前检查这五项#

检查项怎么查
手机 375px 不横向滚浏览器开发者工具切 iPhone
图片都有 alt看模板里 alt= 有没有写
一页只有一个 h1看模板里 <h1> 数量
统计代码在页脚看 footer.html 有没有 `
备案号在页脚国内站必须有,链到 beian.miit.gov.cn

接下来看哪一章#

我想…去看
语法记不清模板标签速查
加会员、投稿、VIP会员体系
站点变慢性能与缓存
页面报错排错手册
没找到答案? 在后台「缓存与维护 → 系统体检」里看环境是否正常;仍无解就打开 server_debug.php 复现一次,页面会直接告诉你异常文件与行号。