You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hakyll如何为文章列表模板填充包含标签的上下文?

问题根源

你的listContextWith实现中调用getUnderlying时,获取的是当前正在编译的博客索引页(blog.md)的标识符,而非每一篇单独文章的标识符,因此无法读取到单篇文章的tags元数据,导致标签区域渲染为空。

修复步骤

1. 新增标签字段生成函数

新增专门从单篇文章元数据提取标签的辅助函数:

import Hakyll (trim, splitAll, lookupString, getMetadata, getUnderlying, fromFilePath, listField, defaultContext)

-- 从当前文章的元数据提取标签,生成模板可用的列表字段
tagsField :: String -> Context String
tagsField key = listField key defaultContext $ do
    postId <- getUnderlying
    metadata <- getMetadata postId
    let tags = maybe [] (map trim . splitAll ",") $ lookupString key metadata
    -- 生成标签对应的Item,模板中可直接用$body$读取标签内容
    return $ map (\tag -> Item (fromFilePath $ "tag-" ++ tag) tag) tags

2. 调整文章上下文

把标签字段绑定到单篇文章的上下文postCtx中,同时补充你模板需要的preview字段:

postCtx :: Context String
postCtx =
  dateField "date" "%d/%m/%Y"
  <> tagsField "tags" -- 注入标签列表字段
  -- 若预览内容直接写在文章元数据的preview字段中,可删除下一行,defaultContext会自动读取
  <> snippetField "preview" -- 自动生成文章摘要作为预览,按需使用
  <> defaultContext

3. 简化索引页编译逻辑

你原来的listContextWith、listContext、tagContext都可以直接删除,直接使用修改后的postCtx作为文章列表的上下文即可:

main = do
    ...
    match "blog.md" $ do
      route   $ setExtension "html"
      compile $ do
        posts <- recentFirst =<< loadAll "posts/*"
        let indexCtx =
                listField "posts" postCtx (return posts) `mappend`
                defaultContext
        pandocCompiler
          >>= loadAndApplyTemplate "templates/blogindex.html" indexCtx
          >>= relativizeUrls

原理解释

把tagsField绑定到postCtx后,每次渲染单篇文章条目时,getUnderlying获取的就是对应文章的标识符,能够正确读取单篇文章的tags元数据,和你的模板逻辑完全匹配。


内容的提问来源于stack exchange,提问作者iluvAS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:39:02