QUICK FIND

搜索站点内容

输入关键词开始搜索,无需连接服务器。

⌘ K 随时打开,按 Esc 关闭

模板与页面数据

使用编译器提供的站点、文章、文档树、分页和归档数据。

BookX 使用 Go 的 html/template。每个布局接收一份页面数据,其中 .Site 是全站信息,.Page 是当前页面信息,其他字段按页面类型提供。不要假定每个页面都有 .Post.Doc.Pagination

一个列表布局

在继承 Paper 的主题中,下面可以作为 layouts/list.html,复用父主题的页头、页脚和分页:

{{ define "layout" }}
{{ template "head" . }}
{{ template "header" . }}
<main class="site-frame page-main">
  <header class="page-heading">
    <h1>{{ .Page.Title }}</h1>
    <p>{{ .Page.Description }}</p>
  </header>
  <ul>
    {{ range .Posts }}
    <li><a href="{{ .URL }}">{{ .Title }}</a> <time>{{ .DateText }}</time></li>
    {{ end }}
  </ul>
  {{ template "pagination" . }}
</main>
{{ template "footer" . }}
{{ end }}

rangewith 会改变当前的 .。如果在循环中需要访问页面根数据,使用 $,例如 $.Site.Title。普通标题和文本保留模板自动转义,不要为了方便拼接而转换成不受检查的 HTML。

通用字段

字段用途
.Site.Title.Site.Description站点名称与介绍
.Site.HomeURL.Site.BlogURL.Site.ArchiveURL已处理部署子路径的导航地址
.Site.DocsEnabled.Site.ProjectsEnabled.Site.LinksEnabled是否展示对应入口
.Site.DocCollections顶部文档合集列表
.Site.AssetsURL未合并主题资源的 URL 前缀
.Site.BundleCSSURL.Site.BundleJSURL已生成的资源合并地址,未启用时为空
.Site.SearchDataURL静态搜索索引地址
.Page.Title.Page.Description.Page.URL当前页面标题、描述与地址
.Page.Canonical.Page.Kind正式规范地址与页面类型
.Year构建内容对应的年份,用于页脚等展示

这些 URL 字段已经处理站点子路径,不要再手工拼接一次 base_path。也不要把 /assets/theme//blog/ 写死到模板中。

文章、首页与分页

列表页的 .Posts 已完成排序与分页,只负责逐项渲染。首页使用 .HomePosts 获取按当前布局分页数量限制的最近文章;首页旧 .Posts 只保留最近 4 篇以兼容旧主题。文章总数使用 .Site.PostCount,不能用首页列表长度代替。

文章详情使用 .Post 获取元信息,.Content 输出已经编译的正文,.Newer.Older 是可选前后文章。.TOC 提供标题的 IDTextLevel。分类和标签链接可使用文章的 .CategoryURL.TagLinks,无需自己从名称生成 URL。

.Pagination 包含当前页 Current、总页数 TotalPrevURLNextURLPageURLs。每个页码还包含 CurrentEllipsis 状态;省略项不是链接。直接复用父主题 pagination 可保持长页码列表、键盘访问和子路径行为一致。

文档数据

文档列表页使用 .Collections。文档详情的 .Collection 是当前合集,.Doc 是当前页面,.Sidebar 是已经整理好的导航树,.Breadcrumbs 是面包屑。

导航节点的 Children 表示下级,ActiveOpen 表示选中与展开状态。节点有标题但没有 URL 时,渲染为可展开目录或纯文字,不要制造一个不存在的首页链接。面包屑 URL 为空时也应输出文字。

顶级合集保留首页;子目录关闭首页后仍可有下级内容。主题应使用编译器给出的树,不要遍历全部文档后自行重建父子关系。页内目录与左侧文档树也应分别渲染。

归档分批展示

新主题使用 .Archive.Years 渲染当前静态页,每个分组有 Year、全年总数 Count 和本页 PostsCount 不能换成 len .Posts,因为一个年份可能跨过多批。

归档首页的 .Archive.NextDataURL 指向下一批 JSON;没有更多数据时为空。编译器每批最多输出 50 篇,JSON 中只包含列表字段及下一批地址,主题不需要自己判断年份文件名或拼接 JSON 路径。

共享 archive.js 依赖以下模板标记:

标记位置
data-archive-groups所有年份的容器
data-archive-year年份区块,值为年份
data-archive-id每个文章链接,值为稳定内容 ID
data-archive-loaddata-next加载区及下一批 JSON URL
data-archive-moredata-archive-status加载按钮与状态提示
data-archive-pagination完成后需要隐藏的静态分页容器

脚本还复用 archive-yeararchive-year-labelarchive-year-posts 等结构类名。若保留共享加载逻辑,建议从 Paper 的 archive.html 开始修改,保证静态与追加内容的结构一致。

失败时保留重试和静态分页;全部加载完成后隐藏按钮与分页,仅显示完成提示。旧 .ArchiveYears 仍是完整列表,供尚未接入分批加载的自定义主题使用。

评论、搜索与 SEO

复用 headcomments 以及搜索相关模板,可以保留规范地址、分享信息、稳定评论关联和按需加载行为。评论是否启用以 .Comments 数据为准,不根据页面类型硬编码开启。

搜索索引由 .Site.SearchDataURL 提供,打开搜索时再请求即可。不要在每个页面初始化时额外下载全部搜索数据;归档也使用自身的精简分片,不用搜索索引冒充归档数据。

完整字段以源码的 internal/bookx/models.go 为准,现有模板位于 themes/paper/。新增页面需求若需要新的内容关系,应先在编译核心建立清晰的数据协议,再由主题渲染。

Conversation

讨论这篇内容

评论由 GitHub Discussions 提供 · 打开讨论仓库