xiaoheiAh's blog
最近使用Hugo作为博客引擎后,闲不下来总想去找一些简单好看的主题.在官方的主题列表搜罗了一圈后,选择了yinyang,非常简单,但是用了一段时间还是想找个功能全点的,无意中瞄到了一个博主的博客,主题特别吸引我,但是是
hexo
平台的,搜了半天也没有人移植,就自己来吧~ 移植的过程中,遇到了挺多问题,也是这些问题慢慢的熟悉了hugo的模板结构.下面就来写一写自己遇到的问题~
hugo的页面有基本的变量(我更愿意称为属性,根据这些属性来实现我们的主题模板.最主要的有三类:Site
, Page
, Taxonomy
.
站点相关的属性,即config.toml(yml)文件中的配置.
在页面模板中,我们可以使用{{- .Site.Autor }}
这样的方式来获取你想要的站点属性.具体的站点属性可以查看https://gohugo.io/variables/site/. .Site
属于全局配置,在 作用域 得当的情况下是可以正常调用的.非正常情况我们下面再讲.
.Site.Pages
: 获取所有文章(包含生成的一些分类页,比如说 标签页
),按时间倒序排序.返回是一个数组.我们经常用来渲染一个列表.比如 归档
页面.
.Site.Taxonomies
: 获取所有的分类(这里的分类是广义上的),可以获取到按tag
分类的集合,也可以获取到按category
分类的集合,可以用这个属性来完成分类
的页面.下面这段代码就代表着我可以拿到所有的 分类页
,循环得到分类页的链接和标题.
{{- range .Site.Taxonomies.categories }}
<li><a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a></li>
{{- end }}
.Site.Params
可以获取到我们在config.toml
的Params
标签下设置的内容.也是很重要的属性.比如说下面的例子.我可以设置日期的格式化样式,展示成你想要的类型.<p>{{ .Date.Format (.Site.Params.dateFormatToUse | default "2006-01-02")}}</p>
页面中定义的属性.
页面属性可以大致分为两部分,一个是Hugo
原生的属性,一个是每一篇文章的文件头,即front matter
中的属性.具体的属性可以在https://gohugo.io/variables/page/查看. 在一个页面的作用域中使用时可以直接调用.比如我们想要知道页面的创建日期就可以直接 {{ .Date }}
即可.
.Date/.Title/.ReadingTime/.WordCount
见名知意.Permalink/.RelPermalink
永久链接及相对连接.Summary
摘要,默认70字.Pages
为什么页面中还有一个这样的属性呢? Page
是包含生成的分类页
, 标签页
的,所有当处于这些页面时会返回一个集合,若是我们自己真正写的文件,即markdown
文件,会返回nil
的.用作内容分类的管理. 我们经常在写文章时会写上
categories
或者tags
, 这些标签类目就是.Taxonomies
的集中展示,Hugo
默认会有categories
和tags
两种分类. 你也可以自己再自定义设置. 具体参考: https://gohugo.io/content-management/taxonomies
官方提供了多种
Template
实现常用的遍历.
我通常会用来写标签页(tags
)和分类页(categories
). 直接调用 .Taxonomies
会获得所有的分类项(即: tags
, categories
, 自定义分类项
), .Taxonomies.tags
就可以获得所有的标签,以及标签下的所有文章.以下就是我的主题中 标签
页的实现逻辑.
{{- $tags := .Site.Taxonomies.tags }}
<main class="main" role="main">
<article class="article article-tags post-type-list" itemscope="">
<header class="article-header">
<h1 itemprop="name" class="hidden-xs">{{- .Title }}</h1>
<p class="text-muted hidden-xs">{{- T "total_tag" (len $tags) }}</p>
<nav role="navigation" id="nav-main" class="okayNav">
<ul>
<li><a href="{{- "tags" | relURL }}">{{- T "nav_all" }}</a></li>
{{- range $tags }}
<li><a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a></li>
{{- end }}
</ul>
</nav>
</header>
<!-- /header -->
<div class="article-body">
{{- range $name, $taxonomy := $tags }}
<h3 class="panel-title mb-1x">
<a href="{{ "/tags/" | relURL}}{{ $name | urlize }}" title="#{{- $name }}"># {{ $name }}</a>
<small class="text-muted">(Total {{- .Count }} articles)</small>
</h3>
<div class="row">
{{- range $taxonomy }}
<div class="col-md-6">
{{ .Page.Scratch.Set "type" "card"}}
{{- partial "item-post.html" . }}
</div>
{{- end }}
</div>
{{- end }}
</div>
</article>
</main>
刚开始写 Hugo 的页面时,最让我头疼的地方就在在于此.现在想想他的逻辑是很标准的.不同的代码块上下文隔离.
在Hugo中,上下文的传递一般是靠.
符号来完成的. 用的最多的就是再组装页面时,需要将当前页面的作用域传递到 partial
的页面中去以便组装进来的页面可以获得当前页面的属性.
以下是我的 baseof.html
页面, 可以看到 partial
相关的代码中都有 .
符号, 这里就是将当前页面的属性传递下去了, 其他页面也就可以正常使用该页面的属性了.
<!DOCTYPE html>
<html lang="{{ .Site.Language }}">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>
{{- block "title" . -}}
{{ if .IsPage }}
{{ .Title }} - {{ .Site.Title }}
{{ else}}
{{ .Site.Title}}{{ end }}
{{- end -}}
</title>
{{ partial "head.html" . }}
</head>
<body class="main-center" itemscope itemtype="http://schema.org/WebPage">
{{- partial "header.html" .}}
{{- if and (.Site.Params.sidebar) (or (ne .Params.sidebar "none") (ne .Params.sidebar "custom"))}}
{{- partial "sidebar.html" . }}
{{end}}
{{ block "content" . }}{{ end }}
{{- partial "footer.html" . }}
{{- partial "script.html" . }}
</body>
</html>
baseof
可以理解为一种模板,符合规范定义的页面都会按照 baseof.html
的框架完成最后的渲染,具体可以查看官网页, 以本次移植主题的 baseof.html
来说一下.
<!DOCTYPE html>
<html lang="{{ .Site.Language }}">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>
{{- block "title" . -}}
{{ if .IsPage }}
{{ .Title }} - {{ .Site.Title }}
{{ else}}
{{ .Site.Title}}{{ end }}
{{- end -}}
</title>
{{ partial "head.html" . }}
</head>
<body class="main-center" itemscope itemtype="http://schema.org/WebPage">
{{- partial "header.html" .}}
{{- if and (.Site.Params.sidebar) (or (ne .Params.sidebar "none") (ne .Params.sidebar "custom"))}}
{{- partial "sidebar.html" . }}
{{end}}
{{ block "content" . }}{{ end }}
{{- partial "footer.html" . }}
{{- partial "script.html" . }}
</body>
</html>
可以看到上面的页面中就是一个完整的 HTML
结构,我在其中组装了很多页面,比如head
,header
,footer
等等,这些在最后渲染的时候都会加入进来组成一个完整的页面.
在上面还有一个关键字 block, 比如 {{ block "title" }}
, {{ block "content"}}
.该关键字允许你自定义一个模板嵌进来, 只要按照规定的方式来.比如说我的文章页 single.html
.
{{- define "content"}}
<main class="main" role="main">
{{- partial "article.html" . }}
</main>
{{- end}}
这里我们定义了 content
的模板, 和 baseof.html
的模板呼应,在渲染一篇文章时,就会将single.html
嵌入 baseof.html
生成最后的页面了.
Hugo要怎么知道文章页还是标签页对应的模板是什么呢?答案: 有一套以多个属性作为依据的查询各类模板的标准.具体可以查看官网页.
以文章页来举例, Hugo
官网上的内容页寻址规则如下:
由上可见,会按照该顺序依次往下找,我一般会写在layouts/_default/single.html
下,这样可以在所有页面下通用.
这里有个小坑也是之前文档没看好遇到的: 标签页和分类页这种对应的查找规则要按照该指引.