从抛弃 Jekyll 转向 Hugo 搞毫无用处的静态站到现在,全程就是在不停的 Ctrl+C 和 Ctrl+V。别人的主题用久了也腻了,于是翻来找去从 printempw 那儿继续 Ctrl+C 了一个主题,不过这次是自己从零开始。在写分页导航的时候遇到了不少问题,也查了不少资料,简单记录一下。自定义 Hugo 的分页导航栏Hugo 内置了 Pagination 导航模板,用内置的模板是一般情况下最省心的解决方案,官方文档提供了两种方案如下:{{ $paginator := .Paginate (where .Pages "Type" "posts") }} {{ template "_internal/pagination.html" . }} {{ range $paginator.Pages }} {{ .Title }} {{ end }} {{ template "_internal/pagination.html" . }} {{ range .Paginator.Pages }} {{ .Title }} {{ end }} 在创建普通 list 页面的时候使用下面的方案即可,但在创建例如 Fuji 主题的主页 list 的时候,由于需要对获取的文章进行筛选,因此需要用到上一种解决方案。对内置模板的小改动来看一下使用内置导航模板生成的 HTML 内容:<ul class="pagination"> <li class="page-item"> <a href="/" class="page-link" aria-label="First"> <span aria-hidden="true">««</span> </a> </li> <li class="page-item disabled"> <a class="page-link" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li class="page-item active"><a class="page-link" href="/">1</a></li> <li class="page-item"><a class="page-link" href="/page/2/">2</a></li> <li class="page-item"><a class="page-link" href="/page/3/">3</a></li> <li class="page-item disabled"> <span aria-hidden="true"> … </span> </li> <li class="page-item"><a class="page-link" href="/page/5/">5</a></li> <li class="page-item"> <a href="/page/2/" class="page-link" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> <li class="page-item"> <a href="/page/5/" class="page-link" aria-label="Last"> <span aria-hidden="true">»»</span> </a> </li> </ul> 导航栏内部元素中,中间被省略的数字会被添加一个 disabled 类,当处在第一页或最后一页时,相对应的上一页和下一页的链接也会被添加这个类。当前的页面会被添加 active 类。只需根据不同的类进行 CSS 修正即可,例如:ul.pagination li.page-item { display: inline; // 移除处于第一页时的前一页和处于最后一页时的下一页 // 注意:此处会将数字之间的省略号一起移除,仍需完善 &.disabled { display: none; } // 移除没有大用处的第一页和最后一页的直接跳转链接 &:first-child, &:last-child { display: none; } } 如何自建导航栏对于想要更进一步自定义的情况,内置的分页导航栏就不够用了,需要自建导航栏。以需要筛选内容的首页为例,首先需要获取分页变量:{{ $paginator := .Paginator }} 其次可以通过判断有几个分页来决定是否显示分页导航栏:{{ if gt $paginator.TotalPages 1 }} <!-- 分页导航栏 --> {{ end }} 获取所有的分页代号,并写入导航栏中,并为当前页面添加特殊类:<ul class="pagination"> {{ range $paginator.Pagers }} <li class="pag-item{{ if eq . $paginator }} pag-current{{ end }}"> <a href="{{ .URL }}" class="pag-link">{{ .PageNumber }}</a> </li> {{ end }} </ul> 添加上一页的链接,下一页同理:{{ if $paginator.HasPrev }} <li class="pag-item pag-previous"> <a href="{{ $paginator.Prev.URL }}" class="pag-link"></a> </li> {{ end }} 智能导航栏现在基本的导航栏已经成型了,但是最大的问题是当页面过多的时候,将所有页号都显示出来一定会使导航栏变得很长,为了解决这个问题现在需要这些功能:当前页面需要显示在导航栏内当有很多页面时,导航栏将展示出当前页面前后的几页显示出的页码个数不能超过限制例如当有十个页面时,并且定义 $offsetLinks = 2 时希望实现如下图的效果:最大可显示的页码数 $maxLinks = ($offsetLinks * 2) + 1如果总页面数小于 $maxLinks,那么所有页码正常显示当前页面为 1-3 和 8-10 时的显示与其他不同,需要独立定义以上这条引出上下限变量 $lowerLimit = $offsetLinks + 1 和 $upperLimit = .TotalPages - $offsetLinks变量在模板中定义这些变量:{{ $offsetLinks := 2 }} <!-- $maxLinks = ($offsetLinks * 2) + 1 --> {{ $maxLinks := (add (mul $offsetLinks 2) 1) }} <!-- $lowerLimit = $offsetLinks + 1 --> {{ $lowerLimit := (add $offsetLinks 1) }} <!-- $upperLimit = $paginator.TotalPages - $offsetLinks --> {{ $upperLimit := (sub $paginator.TotalPages $offsetLinks) }} 在 {{ range $paginator.Pagers }} 的循环内,使用 Hugo 的 scratchpad 来定义一个页码 flag 布尔变量。用这玩意来显示或隐藏页码,默认设置为 false。{{ range $paginator.Pagers }} {{ $.Scratch.Set "pageNumFlag" false }} {{ end }} 使用 .Scratch 的原因是因为 if 段内定义的局部变量外部无法访问。页码数不够多的情况如果总页面数小于 $maxLinks,那么所有页码正常显示:{{ range $paginator.Pagers }} {{ $.Scratch.Set "pageNumFlag" false }} <!-- 页码数足够多的情况 --> {{ if gt $paginator.TotalPages $maxLinks }} <!-- ... --> {{ else }} <!-- 页码数不够多的情况 --> {{ $.Scratch.Set "pageNumFlag" true }} {{ end }} {{ if eq ($.Scratch.Get "pageNumFlag") true }} <li class="pag-item{{ if eq . $paginator }} pag-current{{ end }}"> <a href="{{ .URL }}" class="pag-link">{{ .PageNumber }}</a> </li> {{ end }} {{ end }} 页码数足够多的情况以下为基本思路,详情请见最终代码:<!-- 如果当前页面为例子中的 1-3 区间 --> {{ if le $paginator.PageNumber $lowerLimit }} <!-- ... --> <!-- 如果当前页面为例子中的 8-10 区间 --> {{ else if ge $paginator.PageNumber $upperLimit }} <!-- ... --> <!-- 如果当前页面为例子中的 4-7 区间 --> {{ else }} <!-- ... --> {{ end }} 最终整体代码<!-- 开始 输出一定数量的位于 posts 分类下的文章 --> {{ $paginator := .Paginate (where .Data.Pages "Type" "posts") }} {{ range $paginator.Pages }} <div class="post"> <h2 class="post-title"> <a href="{{ .Permalink }}">{{ .Title }}</a> </h2> <div class="post-summary"> {{ .Summary }} </div> </div> {{ end }} <!-- 结束 输出一定数量的位于 posts 分类下的文章 --> <!-- 开始 分页导航 --> {{ $paginator := .Paginator }} <!-- 基础偏移变量 --> {{ $offsetLinks := 2 }} <!-- $maxLinks = ($offsetLinks * 2) + 1 --> {{ $maxLinks := (add (mul $offsetLinks 2) 1) }} <!-- $lowerLimit = $offsetLinks + 1 --> {{ $lowerLimit := (add $offsetLinks 1) }} <!-- $upperLimit = $paginator.TotalPages - $offsetLinks --> {{ $upperLimit := (sub $paginator.TotalPages $offsetLinks) }} <!-- 如果有超过一页的内容 (即需要导航栏) --> {{ if gt $paginator.TotalPages 1 }} <ul class="pagination"> <!-- 上一页 --> {{ if $paginator.HasPrev }} <li class="pag-item pag-previous"> <a href="{{ $paginator.Prev.URL }}" class="pag-link">«</a> </li> {{ end }} <!-- 数字页码部分 --> {{ range $paginator.Pagers }} {{ $.Scratch.Set "pageNumFlag" false }} <!-- 页码数足够多的情况 --> {{ if gt $paginator.TotalPages $maxLinks }} <!-- 如果当前页面为例子中的 1-3 区间 --> {{ if le $paginator.PageNumber $lowerLimit }} {{ if le .PageNumber $maxLinks }} {{ $.Scratch.Set "pageNumFlag" true }} {{ end }} <!-- 如果当前页面为例子中的 8-10 区间 --> {{ else if ge $paginator.PageNumber $upperLimit }} {{ if gt .PageNumber (sub $paginator.TotalPages $maxLinks) }} {{ $.Scratch.Set "pageNumFlag" true }} {{ end }} <!-- 如果当前页面为例子中的 4-7 区间 --> {{ else }} {{ if and ( ge .PageNumber (sub $paginator.PageNumber $offsetLinks) ) ( le .PageNumber (add $paginator.PageNumber $offsetLinks) ) }} {{ $.Scratch.Set "pageNumFlag" true }} {{ end }} {{ end }} <!-- 页码数不够多的情况 --> {{ else }} {{ $.Scratch.Set "pageNumFlag" true }} {{ end }} <!-- 输出页码 --> {{ if eq ($.Scratch.Get "pageNumFlag") true }} <li class="pag-item{{ if eq . $paginator }} pag-current{{ end }}"> <a href="{{ .URL }}" class="pag-link"> {{ .PageNumber }} </a> </li> {{ end }} {{ end }} <!-- 下一页 --> {{ if $paginator.HasNext }} <li class="pag-item pag-next"> <a href="{{ $paginator.Next.URL }}" class="pag-link">»</a> </li> {{ end }} </ul> {{ end }} 参考Pagination | HugoHow to build custom Hugo pagination | Glenn McCombHugo Pagination | Oliver Schmid