模板方法:对象关联的操作方式
在 Hugo 模板系统中,方法是与特定对象关联的操作,它们提供了访问数据和执行操作的强大机制。理解方法的工作原理是掌握 Hugo 模板开发的关键。
方法与函数的区别
方法特征
方法具有以下特征:
- 对象关联:方法总是与特定对象绑定
- 点号调用:通过点号(
.
)将方法链接到对象 - 上下文相关:方法的可用性取决于当前对象类型
与函数的对比
{{/* 函数调用 */}}
{{ len .Pages }} <!-- 函数,接受参数 -->
{{ add 1 2 }} <!-- 函数,独立存在 -->
{{/* 方法调用 */}}
{{ .Title }} <!-- 方法,属于页面对象 -->
{{ .Site.Title }} <!-- 方法,属于站点对象 -->
{{ .Date.Format "2006-01-02" }} <!-- 方法,属于时间对象 -->
核心对象及其方法
Page 对象方法
Page 对象是最常用的对象,提供了丰富的方法:
{{/* 基本信息方法 */}}
{{ .Title }} <!-- 页面标题 -->
{{ .Description }} <!-- 页面描述 -->
{{ .Date }} <!-- 发布日期 -->
{{ .Lastmod }} <!-- 最后修改时间 -->
{{ .Kind }} <!-- 页面类型 -->
{{/* 内容相关方法 */}}
{{ .Content }} <!-- 页面内容 -->
{{ .Summary }} <!-- 页面摘要 -->
{{ .Plain }} <!-- 纯文本内容 -->
{{ .WordCount }} <!-- 字数统计 -->
{{ .ReadingTime }} <!-- 阅读时间 -->
{{/* 导航相关方法 */}}
{{ .Permalink }} <!-- 永久链接 -->
{{ .RelPermalink }} <!-- 相对永久链接 -->
{{ .Ref "other-page" }} <!-- 页面引用 -->
{{ .RelRef "other-page" }} <!-- 相对页面引用 -->
{{/* 层级关系方法 */}}
{{ .Parent }} <!-- 父级页面 -->
{{ .Children }} <!-- 子页面集合 -->
{{ .Ancestors }} <!-- 祖先页面 -->
{{ .CurrentSection }} <!-- 当前章节 -->
Site 对象方法
Site 对象提供站点级别的信息和操作:
{{/* 站点基本信息 */}}
{{ .Site.Title }} <!-- 站点标题 -->
{{ .Site.BaseURL }} <!-- 基础 URL -->
{{ .Site.Language }} <!-- 当前语言 -->
{{ .Site.Copyright }} <!-- 版权信息 -->
{{/* 页面集合方法 */}}
{{ .Site.Pages }} <!-- 所有页面 -->
{{ .Site.RegularPages }} <!-- 常规页面 -->
{{ .Site.Sections }} <!-- 所有章节 -->
{{/* 配置和数据 */}}
{{ .Site.Params }} <!-- 站点参数 -->
{{ .Site.Data }} <!-- 数据文件 -->
{{ .Site.Menus }} <!-- 菜单配置 -->
{{/* 多语言支持 */}}
{{ .Site.IsMultiLingual }} <!-- 是否多语言 -->
{{ .Site.Languages }} <!-- 所有语言 -->
Time 对象方法
时间对象提供了丰富的日期处理方法:
{{/* 基本时间方法 */}}
{{ .Date.Format "2006-01-02" }} <!-- 格式化日期 -->
{{ .Date.Year }} <!-- 年份 -->
{{ .Date.Month }} <!-- 月份 -->
{{ .Date.Day }} <!-- 日期 -->
{{/* 时间比较 */}}
{{ .Date.Before now }} <!-- 早于当前时间 -->
{{ .Date.After now }} <!-- 晚于当前时间 -->
{{ .Date.Equal .Lastmod }} <!-- 时间相等 -->
{{/* 时间运算 */}}
{{ .Date.AddDate 0 1 0 }} <!-- 增加月份 -->
{{ .Date.Unix }} <!-- Unix 时间戳 -->
高级方法使用技巧
方法链式调用
Hugo 支持方法的链式调用,这是一个强大的特性:
{{/* 链式调用示例 */}}
{{ .Date.Format "2006-01-02" | upper }}
{{ .Title | truncate 50 | markdownify }}
{{ .Resources.GetMatch "*.jpg" | fingerprint }}
{{/* 复杂链式操作 */}}
{{ with .Resources.GetMatch "hero.jpg" }}
{{ $resized := . | resize "800x600" }}
{{ $webp := $resized | images.Process "webp q85" }}
<img src="{{ $webp.RelPermalink }}" alt="{{ $.Title }}">
{{ end }}
方法参数传递
一些方法可以接受参数:
{{/* 带参数的方法 */}}
{{ .Date.Format "January 2, 2006" }}
{{ .Render "summary" }}
{{ .Param "author" }}
{{/* 多参数方法 */}}
{{ .Scratch.Set "key" "value" }}
{{ .GetPage "section" "posts" }}
条件方法调用
结合条件语句使用方法:
{{/* 安全方法调用 */}}
{{ with .Params.author }}
<span class="author">{{ . }}</span>
{{ end }}
{{ if .IsPage }}
<h1>{{ .Title }}</h1>
{{ else if .IsSection }}
<h1>{{ .Title }} 章节</h1>
{{ end }}
{{/* 方法存在性检查 */}}
{{ if .GitInfo }}
<p>最后提交:{{ .GitInfo.Subject }}</p>
{{ end }}
常用方法模式
页面集合处理
{{/* 过滤和排序 */}}
{{ range .Site.RegularPages.ByDate.Reverse }}
{{ if .Params.featured }}
<article class="featured">
<h2>{{ .Title }}</h2>
<p>{{ .Summary }}</p>
</article>
{{ end }}
{{ end }}
{{/* 限制数量 */}}
{{ range first 5 .Site.RegularPages.ByDate.Reverse }}
<h3><a href="{{ .Permalink }}">{{ .Title }}</a></h3>
{{ end }}
资源处理方法
{{/* 页面资源处理 */}}
{{ with .Resources.GetMatch "*.jpg" }}
{{ $thumb := .Resize "300x200" }}
{{ $large := .Resize "1200x800" }}
<a href="{{ $large.Permalink }}">
<img src="{{ $thumb.Permalink }}" alt="{{ $.Title }}">
</a>
{{ end }}
{{/* 全局资源处理 */}}
{{ $sass := resources.Get "scss/main.scss" }}
{{ $css := $sass | resources.ToCSS | resources.Minify }}
<link rel="stylesheet" href="{{ $css.Permalink }}">
数据方法使用
{{/* 访问数据文件 */}}
{{ range .Site.Data.authors }}
<div class="author">
<h3>{{ .name }}</h3>
<p>{{ .bio }}</p>
</div>
{{ end }}
{{/* 动态数据访问 */}}
{{ $authorKey := .Params.author }}
{{ with index .Site.Data.authors $authorKey }}
<p>作者:{{ .name }}</p>
{{ end }}
错误处理与调试
安全方法调用
{{/* 使用 with 避免 nil 指针 */}}
{{ with .GitInfo }}
<p>提交时间:{{ .CommitDate.Format "2006-01-02" }}</p>
{{ end }}
{{/* 使用 default 提供默认值 */}}
{{ .Params.author | default "匿名作者" }}
{{/* 条件检查 */}}
{{ if and .IsPage .Date }}
<time>{{ .Date.Format "2006-01-02" }}</time>
{{ end }}
调试方法输出
{{/* 调试方法返回值 */}}
{{ printf "%#v" .Date }}
{{ printf "%T" .Resources }}
{{/* 输出方法信息 */}}
{{ with .File }}
<!-- 文件路径:{{ .Path }} -->
<!-- 文件名:{{ .LogicalName }} -->
{{ end }}
性能优化技巧
方法调用缓存
{{/* 缓存方法结果 */}}
{{ $pages := .Site.RegularPages }}
{{ range $pages }}
<h3>{{ .Title }}</h3>
{{ end }}
{{/* 避免重复调用 */}}
{{ $site := .Site }}
{{ range $pages }}
{{/* 使用缓存的 $site 而不是 .Site */}}
<a href="{{ .Permalink }}">{{ .Title }}</a>
{{ end }}
条件方法执行
{{/* 按需执行昂贵的方法 */}}
{{ if .Params.processImages }}
{{ range .Resources.ByType "image" }}
{{ $processed := . | resize "800x600" | images.Filter "brightness(110%)" }}
<img src="{{ $processed.RelPermalink }}" alt="">
{{ end }}
{{ end }}
最佳实践
- 理解上下文:始终注意当前的模板上下文,合理使用
.
和$
- 错误处理:对于可能失败的方法调用,使用适当的错误处理
- 性能考虑:避免在循环中重复调用昂贵的方法
- 可读性:使用有意义的变量名来存储方法的返回值
{{/* 良好的实践示例 */}}
{{ $currentPage := . }}
{{ $relatedPages := .Site.RegularPages.Related . | first 3 }}
{{ if $relatedPages }}
<section class="related-posts">
<h3>相关文章</h3>
<ul>
{{ range $relatedPages }}
<li>
<a href="{{ .Permalink }}">{{ .Title }}</a>
<time>{{ .Date.Format "2006-01-02" }}</time>
</li>
{{ end }}
</ul>
</section>
{{ end }}
总结
Hugo 模板方法系统提供了强大而灵活的数据访问和操作能力。通过掌握各种对象的方法、理解方法链式调用、合理处理错误和优化性能,你可以创建出高效且易维护的模板。记住始终关注上下文的变化,并采用防御性编程来确保模板的稳定性。