如何用11ty为_data子文件夹中每个JSON文件生成独立页面?
我之前帮人处理过几乎一模一样的场景:用11ty搭建影评网站,_data/movies下按年份分文件夹存单个电影的JSON文件,想生成_site/movies/年份/标题-slug/index.html这样的页面,一开始卡了好久,后来终于搞定了,分享下解决方案:
问题回顾
你的项目结构是这样的:
_data/movies/2017/title1.json_data/movies/2017/title2.json_data/movies/2018/...
需求是生成对应年份的页面路径,最初的模板里permalink中的年份变量无法正确获取,导致路径生成失败。
解决方案步骤
1. 修正分页配置与Permalink规则
原来的分页配置只遍历到了年份文件夹层级(因为resolve: keys),没拿到单个电影的数据。调整后,我们直接用每个JSON文件中自带的ReleaseYear属性(建议每个电影JSON都加这个字段,比从文件夹路径提取更可靠),同时结合Id和Title生成唯一的URL路径。修改后的Nunjucks模板如下:
--- pagination: data: movies size: 1 alias: movie resolve: deep # 关键:遍历所有嵌套的电影数据条目 permalink: "movies/{{ movie.ReleaseYear }}/{{ movie.Id }}-{{ movie.Title | slug }}/index.html" --- <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ movie.TitleWithYear }}</title> </head> <body> <h1>{{ movie.TitleWithYear }}</h1> </body> </html>
这里的resolve: deep是核心——它会让11ty遍历movies对象下的所有嵌套数据,把每个JSON文件对应的内容作为单独的movie条目处理,这样你就能直接访问到电影的ReleaseYear、Title等属性了。
2. 添加全局Slugify过滤器
为了把电影标题转换成URL友好的字符串,我们需要自定义一个slug过滤器。在项目根目录创建.eleventy.js文件,添加以下代码:
const slugify = require('slugify'); module.exports = function(eleventyConfig) { eleventyConfig.addFilter("slug", function(value) { // strict: true会移除特殊字符,lower: true转小写,确保URL规范 return slugify(value, { strict: true, lower: true }); }); };
别忘了先安装依赖包:
npm install slugify --save-dev
最终效果
现在运行npx @11ty/eleventy生成页面后,就能得到你想要的结构:
_site/movies/2017/1-blade-runner-2049/index.html_site/movies/2018/2-black-panther/index.html
如果暂时不想在JSON里加ReleaseYear,也可以调整分页逻辑先遍历年份文件夹,再遍历每个年份下的电影,但直接在JSON中存储元数据是最灵活、最易维护的方式,后续扩展功能也更方便。
内容的提问来源于stack exchange,提问作者centralscru

