多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Hugo 页面集合(Page Collections)完全指南:Page/Site 方法、where 过滤、排序与分组实战

Hugo 页面集合(Page Collections)完全指南:Page/Site 方法、where 过滤、排序与分组实战 Hugo 页面集合Page Collections完全指南Page/Site 方法、where 过滤、排序与分组实战【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo本指南以 Hugo 官方快速参考文档 page-collections.md 为核心骨架系统讲解 Hugo 模板中最常用的页面集合Page Collections操作如何通过Page与Site方法获取页面集合如何使用where函数过滤集合以及如何对集合进行排序Sort与分组Group。读完本文你将能在首页、section 页、taxonomy 页与 term 页中熟练地取数、过滤、排序并分组渲染任意页面列表并理解这些方法在 Hugo 源码中的真实实现机制。什么是页面集合页面集合Page collection是 Hugo 中的一个核心概念指一组Page对象的组合返回类型为page.Pages。几乎所有列表类模板——无论是首页、section 页、taxonomy 页还是 term 页——都需要先拿到一个页面集合再对其进行过滤、排序、分组和遍历渲染。Hugo 官方将页面集合操作归纳为四类正是本文要展开讲解的全部内容取集合通过Page方法与Site方法获取集合过滤通过where函数按条件筛选排序通过Pages系列的排序方法重排集合分组通过Pages系列的分组方法将集合按键聚合。在 docs/content/en/quick-reference/page-collections.md 中每一类操作都对应一组官方维护的方法清单这些清单由文档站通过短代码render-list-of-pages-in-section定义于 docs/layouts/_shortcodes/render-list-of-pages-in-section.html从 docs/data/page_filters.yaml 中读取过滤器动态渲染因此方法与官方文档保持一致不会出现文档有、代码没有或反之的偏差。Page 方法在列表类页面上取集合当渲染 section 页、taxonomy 页、term 页或首页时模板上下文context中直接携带了一个页面集合。此时应使用Page对象上的以下四个方法获取集合对应的过滤器为methods_page_page_collections见 docs/data/page_filters.yaml方法返回内容可用页面种类.Pages当前 section 内的普通页面以及直接子 section 的 section 页home、section、taxonomy、term.RegularPages当前 section 内的普通页面不含子 section 的页面与 section 页home、section、taxonomy、term.RegularPagesRecursive当前 section 内及其所有后代 section 内的普通页面home、section、taxonomy、term.Sections当前页面的每个直接子 section 对应的 section 页home、section、taxonomy这些方法的模板上下文以默认排序顺序返回集合。典型用法{{ range .Pages.ByTitle }} h2a href{{ .RelPermalink }}{{ .Title }}/a/h2 {{ end }}Pages 与 RegularPages 的差异Pages与RegularPages是列表模板中最常用的一对方法区别在于是否包含子 section 的 section 页。以 Pages.md 中的示例内容结构为例content/ ├── lessons/ │ ├── lesson-1/ │ │ ├── _index.md │ │ ├── part-1.md │ │ └── part-2.md │ ├── lesson-2/ │ │ ├── resources/ │ │ │ ├── task-list.md │ │ │ └── worksheet.md │ │ ├── _index.md │ │ ├── part-1.md │ │ └── part-2.md │ ├── _index.md │ ├── grading-policy.md │ └── lesson-plan.md ├── _index.md ├── contact.md └── legal.md渲染首页时Pages返回contact.md、legal.md、lessons/_index.md渲染 lessons 页时Pages返回grading-policy.md、lesson-plan.md以及lesson-1/_index.md、lesson-2/_index.md两个子 section。而RegularPages在相同场景下不包含任何_index.md首页只返回contact.md、legal.mdlessons 页只返回grading-policy.md、lesson-plan.md。一个容易混淆的细节是lesson-2/resources/目录没有_index.md因此它不是 section其中的task-list.md与worksheet.md会被视为 lesson-2 section 的内容——Pages与RegularPages在渲染 lesson-2 时都会包含它们。RegularPagesRecursive递归取全部普通页面RegularPagesRecursive与RegularPages的区别在于是否跨越 section 层级。在同一个内容结构中渲染 lessons 页时RegularPages只返回grading-policy.md、lesson-plan.md而RegularPagesRecursive还会递归包含lesson-1/、lesson-2/乃至lesson-2/resources/下的全部普通页面见 RegularPagesRecursive.md。注意该方法不适用于Site对象其官方文档 RegularPagesRecursive.md 中明确标注了这一点。Sections遍历子 sectionSections方法返回当前页面的直接子 section 列表适合做子栏目导航。以 Sections.md 中的拍卖网站示例为例通过weight前置参数控制顺序{{ range .Sections.ByWeight }} h2a href{{ .RelPermalink }}{{ .LinkTitle }}/a/h2 {{ end }}在首页上会依次渲染 Films、Books、Auctions按_index.md中weight10/20/30 升序在 auctions 页上则渲染 2023-11 与 2023-12 两个子拍卖 section。Site 方法在任意页面上取全局集合当模板上下文不是列表类页面时例如在单篇内容页、局部模板 partial 中需要从Site对象获取全局页面集合。对应的过滤器为methods_site_page_collections包含四个方法见 docs/data/page_filters.yaml方法返回内容.Site.AllPages所有语言下的全部页面已废弃见下.Site.Pages当前语言下所有页面含首页、section 页、taxonomy 页、term 页、普通页.Site.RegularPages当前语言下所有普通页面.Site.Sections顶层 section 页其中AllPages已在 v0.156.0 版本中标记为废弃其文档 AllPages.md 的 front matter 中expiryDate: 2028-02-18与# deprecated 2026-02-18 in v0.156.0注释可以佐证不应在新代码中使用。与 Page 方法的本质区别递归范围Site对象上的Pages与RegularPages是全站递归的。官方文档在 page/Pages.md 与 page/RegularPages.md 中均以 NOTE 形式提示用于Site对象时方法递归返回站内所有页面/所有普通页面。{{ range .Site.RegularPages.ByTitle }} h2a href{{ .RelPermalink }}{{ .Title }}/a/h2 {{ end }}Site.Pages包含所有页面种类kind官方文档 site/Pages.md 明确建议绝大多数场景应使用Site.RegularPages而非Site.Pages因为后者会混入 section 页、taxonomy 页等非内容页面容易在列表中产生意外条目。Site.Sections则返回顶层 section 列表适合构建站级导航。例如 site/Sections.md 中{{ range .Site.Sections }}会渲染出/books/与/films/两个顶层栏目链接。Filter用 where 函数过滤页面集合获取集合之后最常见的下一步是按条件筛选。Hugo 使用where函数模板别名源码定义见 tpl/collections/where.go完整文档见 functions/collections/Where.md完成过滤其函数签名为collections.Where SLICE KEY [OPERATOR] VALUE -------------------- comparison condition三个必需参数加一个可选参数SLICE是页面集合或 map 切片KEY是要比较的字段如Section、Type、Params访问Params子键可用点号链式写法Params.fooVALUE是比较值。省略OPERATOR时默认做相等eq判断{{ $pages : where .Site.RegularPages Section books }}完整的操作符集合where支持以下逻辑操作符对应 tpl/collections/where.go 第 183286 行中switch op的实现分支其中like操作符通过 common/hstrings/strings.go 的正则缓存编译函数GetOrCompileRegexp匹配操作符语义,,eq字段值等于VALUE!,,ne字段值不等于VALUE,ge大于等于,gt大于,le小于等于,lt小于in字段值标量是VALUE切片或字符串的成员not in字段值标量不是VALUE切片或字符串的成员intersect字段值切片与VALUE切片存在公共元素like字段值字符串匹配VALUE中的正则表达式各类数据类型的比较示例字符串与数值比较{{ $pages : where .Site.RegularPages Section eq books }} {{ $pages : where $books Params.price ge 42 }} {{ $pages : where $books Params.price lt 42.67 }}布尔比较{{ $pages : where $books Params.fiction eq true }}成员比较标量 vs 切片——筛选颜色为 red 或 yellow 的水果页面{{ $colors : slice red yellow }} {{ $pages : where $fruit Params.color in $colors }} {{ $pages : where $fruit Params.color not in $colors }}交集比较切片 vs 切片——常用于 taxonomy 词条匹配返回 genre 同时命中 suspense 或 romance 的图书{{ $genres : slice suspense romance }} {{ $pages : where $books Params.genres intersect $genres }}正则比较——作者名以 victor 或 Victor 开头{{ $pages : where .Site.RegularPages Params.author like (?i)^victor }}日期比较——Hugo 的前置参数date、publishDate、lastmod、expiryDate无论以何种格式书写都会解析为time.Time可精确比较{{ $startOfYear : time.AsTime (printf %d-01-01 now.Year) }} {{ $pages : where .Site.RegularPages Date lt $startOfYear }}需要特别提醒where的VALUE与被比较字段必须数据类型一致否则比较结果为false。例如123 eq 123字符串 vs 整数与false eq false布尔 vs 字符串都不成立这是 functions/collections/Where.md 中明确给出的对比表结论在模板中极易踩坑。Sort对页面集合排序默认排序顺序所有取集合方法返回的集合都遵循 Hugo 的默认排序顺序default sort order。其完整优先级定义在 docs/content/en/quick-reference/glossary/default-sort-order.md依次为weight升序date降序linkTitle未定义时回退到title升序逻辑路径logical path升序。该顺序同时决定了Page对象上Next/Prev等导航方法所依据的相邻页面关系见 configuration/page.md 的说明理解它有助于预测模板输出。排序方法一览Pages集合提供以下排序方法过滤器methods_pages_sort见 docs/data/page_filters.yaml完整方法索引见 methods/pages/_index.md方法排序依据.ByDate日期默认取前置参数date可被项目配置覆盖.ByExpiryDate过期日期expiryDate.ByLanguage语言语言权重升序 → 日期降序 → LinkTitle 升序.ByLastmod最后修改时间lastmod.ByLength内容长度.ByLinkTitle链接标题未定义时回退到标题.ByParam PARAM指定前置参数支持点号访问嵌套如ByParam author.last_name.ByPublishDate发布日期publishDate.ByTitle标题升序.ByWeight权重升序未设置或为 0 的页面排到末尾.Reverse反转当前顺序所有排序方法默认升序链式调用.Reverse即可降序{{ range .Pages.ByDate.Reverse }} !-- 最新在前 -- h2a href{{ .RelPermalink }}{{ .LinkTitle }}/a/h2 {{ end }} {{ range .Pages.ByWeight }} !-- 最轻在前0 权重垫底 -- h2a href{{ .RelPermalink }}{{ .LinkTitle }}/a/h2 {{ end }}关于ByWeight的一个细节weight必须是非零整数未设置或为 0 的页面统一排在集合末尾见 methods/pages/ByWeight.md。日期类排序方法ByDate、ByPublishDate、ByLastmod、ByExpiryDate的取值遵循项目配置默认取前置参数中的对应字段官方文档统一指向 configuration/front-matter 的 dates 章节也就是说你可以通过项目配置改变日期究竟读哪个字段。Group对页面集合分组分组方法将集合按某个键聚合返回page.PagesGroup一组键 页面集合。对应过滤器methods_pages_group包含七个方法方法分组依据.GroupBy FIELD [SORT]指定字段.GroupByDate LAYOUT [SORT]日期默认date字段.GroupByExpiryDate LAYOUT [SORT]过期日期.GroupByLastmod LAYOUT [SORT]最后修改时间.GroupByParam PARAM [SORT]指定前置参数.GroupByParamDate PARAM LAYOUT [SORT]指定日期型前置参数.GroupByPublishDate LAYOUT [SORT]发布日期所有分组方法的可选排序参数只接受asc升序或desc降序两个值见公共片段 docs/content/en/_common/methods/pages/group-sort-order.md省略时按各方法自己的默认方向日期类分组默认降序。按字段分组{{ range .Pages.GroupBy Section }} p{{ .Key }}/p ul {{ range .Pages }} lia href{{ .RelPermalink }}{{ .LinkTitle }}/a/li {{ end }} /ul {{ end }}按参数分组{{ range .Pages.GroupByParam color }} p{{ .Key | title }}/p ul {{ range .Pages }} lia href{{ .RelPermalink }}{{ .LinkTitle }}/a/li {{ end }} /ul {{ end }}按日期分组日期类分组方法的LAYOUT参数与time.Format的布局字符串格式一致例如January 2006且分组键会根据语言与区域本地化。按年月归档是典型用法{{ range .Pages.GroupByDate January 2006 }} p{{ .Key }}/p ul {{ range .Pages.ByTitle }} !-- 组内再按标题排序 -- lia href{{ .RelPermalink }}{{ .Title }}/a/li {{ end }} /ul {{ end }}组内页面默认也按日期排序方向与分组方向一致需要其他组内顺序时可在range .Pages上继续链式调用排序方法。若需按自定义日期字段归档改用GroupByParamDate它多一个参数用于指定字段名{{ range .Pages.GroupByParamDate eventDate January 2006 asc }} p{{ .Key }}/p ul {{ range .Pages }} lia href{{ .RelPermalink }}{{ .LinkTitle }}/a/li {{ end }} /ul {{ end }}实战组合过滤 排序 分组将四类操作串联起来是列表模板的常见形态。下面是一个完整示例在首页取出全站普通页面 → 过滤出bookssection → 按价格参数升序 → 按作者分组渲染{{ $books : where .Site.RegularPages Section eq books }} {{ $booksByAuthor : $books.ByParam author | groupBy Params.author }} {{ range $booksByAuthor }} h2{{ .Key }}/h2 ul {{ range .Pages.ByTitle }} lia href{{ .RelPermalink }}{{ .Title }}/a — ${{ .Params.price }}/li {{ end }} /ul {{ end }}提示GroupBy系列也可以作用于经由where过滤后的中间集合二者可以自由链式组合但注意 Go 模板管道中where返回的是[]any类型切片必要时先用sort等其他集合函数转换类型再调用集合方法具体行为可参考 tpl/collections/where_test.go 中的测试用例。源码与测试佐证以上 API 并非文档虚构全部可以在仓库源码与测试中找到实现证据where 操作符实现tpl/collections/where.go 第 183286 行的switch op分支逐一实现了eq/ne/ge/gt/le/lt/in/not in/intersect/like全部操作符与文档表格一一对应集合类型所有取集合方法的返回类型为page.Pages在 hugolib/pagecollections.go页面集合装配与 hugolib/pages_test.go含BenchmarkPagePageCollections基准测试中可见页面集合的构建与性能关注文档自动生成机制docs/data/page_filters.yaml 定义了methods_page_page_collections、methods_site_page_collections、methods_pages_sort、methods_pages_group等过滤器docs/layouts/_shortcodes/render-list-of-pages-in-section.html 根据它们动态列出方法与说明确保本文所列方法清单与 Hugo 实际 API 同步。小结页面集合是 Hugo 模板体系的地基Page方法解决当前页面上下文里有什么Site方法解决全站范围内有什么where负责按条件挑排序方法负责按规则排分组方法负责按键聚合。掌握这四类操作并理解默认排序顺序与where的严格类型比较规则即可应对绝大多数列表、归档与导航模板的编写需求。相关方法的逐一说明均可继续查阅 methods/page 与 methods/pages 目录下的独立文档。【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表