Hugo Page.Weight 方法实战指南:用 front matter 权重精确控制页面排序
【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo
Page.Weight是 Hugo 页面对象上用于读取页面"权重"的方法,返回值为int类型,数据来源于页面 front matter 中定义的weight字段。它是 Hugo 默认页面排序规则中的第一排序依据,常用于控制博客文章在列表中的先后顺序、让置顶内容浮到集合顶部等场景。读完本文,你将掌握weight的正确设置方式、Weight 参与排序的底层规则,以及如何在模板中读取和利用这一字段。
Weight 方法是什么
在 Hugo 中,Page对象提供了一个Weight方法,其完整签名为PAGE.Weight,返回值类型为int。它返回的是该页面在 front matter 中定义的 weight(即页面权重)。
在源码层面,该方法的实现位于 hugolib/page__meta.go#L537-L539:
func (m *pageMeta) Weight() int { return m.pageConfig.Weight }也就是说,Weight()直接返回页面配置对象pageConfig中的Weight字段,而这个字段的定义位于 resources/page/pagemeta/page_frontmatter.go#L160:
Weight int // The weight of the page, used in sorting if set to a non-zero value.同时在 resources/page/page.go#L257-L259 的Page接口中,Weight()被明确注释为:
// The configured weight, used as the first sort value in the default // page sort if non-zero. Weight() int从源码可以确认:Weight 是默认页面排序中的第一个(权重非零时)排序值,这正是它在 Hugo 内容组织中的核心价值。
在 front matter 中设置 Weight
weight是 Hugo 的保留前置元数据字段,直接在页面 front matter 中声明即可。原文档给出的 TOML 示例如下:
# content/recipes/sushi.md title = 'How to make spicy tuna hand rolls' weight = 42使用 YAML 格式时写法相同,只是语法不同:
--- title: 'How to make spicy tuna hand rolls' weight: 42 ---使用 JSON 格式时:
{ "title": "How to make spicy tuna hand rolls", "weight": 42 }Hugo 在解析 front matter 时,会在 hugolib/page__meta.go#L755-L757 对weight关键字做专门处理:
case "weight": pcfg.Weight = cast.ToInt(v) pcfg.Params[loki] = pcfg.Weight可以看到weight的值会通过cast.ToInt被转换为int类型。这意味着即使你在 front matter 中写了字符串形式的数字(例如weight = "42"),Hugo 也会将其安全地转换为整数 42;但建议直接使用整数字面量,语义更清晰。
Weight 的排序规则:轻者在上,重者在下
Weight 的核心作用是控制页面在按权重排序的集合中的位置。规则可以概括为三点:
- 使用非零整数分配权重;
- 权重小的(轻的)排在前面,权重大的(重的)排在后面,即数值越小越靠前;
- 未设置权重或权重为 0 的元素,统一被排到集合末尾。
例如,两个页面分别设置weight = 10和weight = 20,则前者必然排在后者之前;而完全未声明weight的页面,会落在所有已加权页面之后。
这套行为在源码中有明确对应。Hugo 的默认排序函数DefaultPageSort定义于 resources/page/pages_sort.go#L84-L104:
// DefaultPageSort is the default sort func for pages in Hugo: // Order by Ordinal, Weight, Date, LinkTitle and then full file path. DefaultPageSort = func(p1, p2 Page) bool { o1, o2 := getOrdinals(p1, p2) if o1 != o2 && o1 != -1 && o2 != -1 { return o1 < o2 } // Weight0, as by the weight of the taxonomy entrie in the front matter. w01, w02 := getWeight0s(p1, p2) if w01 != w02 && w01 != -1 && w02 != -1 { return w01 < w02 } if p1.Weight() == p2.Weight() { if p1.Date().Unix() == p2.Date().Unix() { c := collatorStringCompare(func(p Page) string { return p.LinkTitle() }, p1, p2) if c == 0 { // This is the full normalized path, which will contain extension and any language code preserved, // which is what we want for sorting. return compare.LessStrings(p1.PathInfo().Path(), p2.PathInfo().Path()) } return c < 0 } ... } ... }由此可以梳理出 Hugo 默认排序的完整优先级链:
- Ordinal(页面序号):用于区分普通页面与分类聚合页面等场景;
- Weight0:分类(taxonomy)条目在 front matter 中定义的权重,普通页面不参与此项比较;
- Weight:本方法返回的页面权重,权重非零时作为主要排序依据;
- Date:页面日期;
- LinkTitle:链接标题;
- 完整文件路径:最后兜底,保证排序结果稳定、确定。
注意:当两个页面Weight值相同时,Hugo 并不会停止比较,而是继续依次回退到日期、链接标题乃至文件路径,因此排序结果始终是确定性的。
在模板中读取 Weight
虽然Weight主要用于排序,但它在模板中同样可以直接访问。原文档给出的示例:
{{ .Weight }} → 42即在任意Page上下文中(例如列表模板的range循环内),使用.Weight即可得到该页面的权重整数值。虽然日常模板中较少直接读取该字段,但当你需要在自定义布局中依据权重做条件判断、调试排序结果或输出权重信息时,它会非常实用。
按权重排序页面集合:ByWeight 与默认排序
Weight发挥作用的主要场景是对页面集合排序。Hugo 为Pages集合提供了ByWeight方法,其实现位于 resources/page/pages_sort.go#L226-L235:
// ByWeight sorts the Pages by weight and returns a copy. // // Adjacent invocations on the same receiver will return a cached result. // // This may safely be executed in parallel. func (p Pages) ByWeight() Pages { const key = "pageSort.ByWeight" pages, _ := spc.get(key, pageBy(DefaultPageSort).Sort, p) return pages }两个值得注意的实现细节:
ByWeight内部实际复用的就是上文提到的DefaultPageSort,因此它的排序结果遵循完整的默认排序链(Weight → Date → LinkTitle → Path),而非仅仅比较 Weight 后不做二次区分;- 排序结果带有缓存(
spc.get),相同接收者上的相邻调用直接命中缓存,且该方法可以安全地并行执行,因此即使在大规模站点中反复调用,性能开销也很低。
ByWeight的典型用法是site.RegularPages.ByWeight。仓库中的集成测试 resources/page/page_integration_test.go#L110-L124 给出了完整的可运行验证示例:
ByWeight: {{ range site.RegularPages.ByWeight }}{{ .Title }}|{{ end }}测试内容为三篇分别设置weight = 1、weight = 2、weight = 3的文章(见 resources/page/page_integration_test.go#L30-L36),期望输出为:
ByWeight: alpha|émotion|zulu|即权重小的排在前、权重大的排在后,与文档规则完全一致。类似的集成测试还出现在 resources/page/pages_prev_next_integration_test.go#L29-L39,其中通过weight: 10、weight: 20、weight: 30验证上一篇/下一篇(Prev/Next)的相邻关系——这说明页面间的 Prev/Next 顺序同样受 Weight 影响。
在模板中,除了ByWeight,还可以使用通用排序函数sort(见 tpl/collections/sort.go)配合字段名"Weight"达到类似效果。此外,分类页面(如 section 列表)在默认情况下也遵循该排序链,因此给 section 页面设置weight同样可以控制其在site.Sections等集合中的先后位置。
进阶辨析:Weight、Weight0 与菜单权重
在使用weight时,有三组容易混淆的概念需要区分清楚:
页面 Weight 与分类 Weight0
上文排序链中的Weight0是分类(taxonomy)条目的权重,由getWeight0s函数读取(resources/page/pages_sort.go#L58-L69),其内部通过types.Weight0Provider接口获取,而普通页面并不实现该接口。从源码结构看,实现该接口的是 hugolib/page.go#L956-L973 中的pageWithWeight0包装类型,它被用于分类场景(见 hugolib/content_map_page.go#L427),携带的是分类术语自身的权重。也就是说,Weight与Weight0是两个不同的机制,分别作用于普通页面与分类条目的排序。
页面 Weight 与菜单权重
菜单项在 front matter 中也有weight字段(见 navigation/menu.go),但它作用于菜单项的排序,与Page.Weight是相互独立的配置,二者互不影响。设置菜单排序时请使用菜单配置或 front matter 中的menus块,而不是Page.Weight。
Weight 与 Date
当Weight为 0 或未设置时,页面会落入集合末尾,此时排序回退到Date。因此:如果希望某页面"置顶",应设置一个较小的正数权重;如果希望"沉底"但仍在其他未加权页面之前,可设置一个较大的正数权重;而完全不加权则意味着交给日期等其他字段决定顺序。
注意事项与最佳实践
- 使用非零整数:
weight为 0 或缺失时页面会被排到加权页面之后,因此想让权重机制真正生效,请务必使用非零整数; - 数值越小越靠前:需要置顶的内容使用小的正数(如
weight = 1),需要靠后的内容使用较大的数(如weight = 100),并预留调整空间; - 权重相同时有确定性的回退规则:Hugo 会继续按日期、链接标题、文件路径比较,不会产生随机顺序;
- 优先用
ByWeight而非手动比较:ByWeight自带缓存且可并行安全调用,适合在列表模板中高频使用; - 区分不同场景的 weight:页面排序、分类术语排序、菜单排序各自使用独立的 weight 机制,不要混用。
通过合理使用weight字段与Page.Weight方法,你可以不依赖日期、不修改文件名,以最简单直观的方式精确控制页面的展示顺序,这也是 Hugo 站点内容组织中最常用的手段之一。
【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考