您如何根据包含标签的 post 的数量对博客 post 标签列表进行排序(使用 Eleventy 中的 Nunjucks)?
How do you sort a list of blog post tags by the number of posts that contain the tag (using Nunjucks in Eleventy)?
我有一个使用 Eleventy(静态站点生成器)构建的博客,使用 Nunjucks 作为模板语言。
我有一个页面列出了我分配给 post 的所有标签。它按字母顺序列出它们,每个标签的数量为 post。
我还想做的是按频率顺序列出标签(最常用的标签在前)。
用于获取字母列表(带计数)的代码如下所示:
<section id="tags-number-of-posts">
{% for tag2, posts2 in collections | dictsort %}
{% set tag2Url %}/tags/{{ tag2 | slug }}/{% endset %}
<a href="{{ tag2Url | url }}">{{ tag2 }} ({{ posts2 | length }})</a><br/>
{% endfor %}
</section>
现在的结果是这样的:
Blender (1)
boats (2)
Bomb Factory (1)
bonfires (4)
books (3)
但我希望它是:
bonfires (4)
books (3)
boats (2)
Blender (1)
Bomb Factory (1)
(您可以在此部署预览站点查看实际结果:https://text-timeline--davidrhoden-basic.netlify.app/tagslist/。)
我试过将 dictsort
更改为 sort(attribute="posts2.length")
,以及其他可能有意义的排列,例如 sort(attribute="length")
,但没有任何效果。
我猜“长度”不是 post 本身的属性。所以也许像 sort
这样的过滤器在这种情况下不起作用。
但是有没有办法根据 post 计数对这个列表进行排序?肯定有。我需要引入 lodash 之类的东西,还是 map
之类的 javascript 函数?
您也许可以使用 Eleventy custom collections 来做您想做的事。我们可以使用.eleventy.js
文件中的Javascript统计每个标签中post的个数,然后按照post的个数对数据进行排序。
因为 Eleventy 似乎没有给我们预先分组的标签对象和 posts,所以我们自己做。这确实意味着,如果您将重复标签放在一个 post 上,它将被计算两次。可以对标签进行重复数据删除,但如果你小心的话,这应该不是问题。
// .eleventy.js
module.exports = function (eleventyConfig) {
// ...
// addCollection receives the new collection's name and a
// callback that can return any arbitrary data (since v0.5.3)
eleventyConfig.addCollection('bySize', (collectionApi) => {
// see https://www.11ty.dev/docs/collections/#getall()
const allPosts = collectionApi.getAll()
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
const countPostsByTag = new Map()
allPosts.forEach((post) => {
// short circuit eval sets tags to an empty array if there are no tags set
const tags = post.data.tags || []
tags.forEach((tag) => {
const count = countPostsByTag.get(tag) || 0
countPostsByTag.set(tag, count + 1)
})
})
// Maps are iterators so we spread it into an array to sort
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
const sortedArray = [...countPostsByTag].sort((a, b) => b[1] - a[1])
// this function returns an array of [tag, count] pairs sorted by count
// [['bonfires', 4], ['books', 3], ['boats', 2], ...]
return sortedArray
})
})
return {
// ...
}
}
然后我们可以在 Nunjucks 中使用这些数据 collections.bySize
。
<section id="tags-number-of-posts">
{# we can still destructure the tag name and count even though it's an array #}
{% for tag, count in collections.bySize %}
{% set tagUrl %}/tags/{{ tag | slug }}/{% endset %}
<a href="{{ tagUrl | url }}">{{ tag }} ({{ count }})</a><br/>
{% endfor %}
</section>
如果您需要在集合对象中包含 post 的数组,而不仅仅是 post 的数量,也可以修改 JavaScript 来执行所以。
我有一个使用 Eleventy(静态站点生成器)构建的博客,使用 Nunjucks 作为模板语言。
我有一个页面列出了我分配给 post 的所有标签。它按字母顺序列出它们,每个标签的数量为 post。
我还想做的是按频率顺序列出标签(最常用的标签在前)。
用于获取字母列表(带计数)的代码如下所示:
<section id="tags-number-of-posts">
{% for tag2, posts2 in collections | dictsort %}
{% set tag2Url %}/tags/{{ tag2 | slug }}/{% endset %}
<a href="{{ tag2Url | url }}">{{ tag2 }} ({{ posts2 | length }})</a><br/>
{% endfor %}
</section>
现在的结果是这样的:
Blender (1)
boats (2)
Bomb Factory (1)
bonfires (4)
books (3)
但我希望它是:
bonfires (4)
books (3)
boats (2)
Blender (1)
Bomb Factory (1)
(您可以在此部署预览站点查看实际结果:https://text-timeline--davidrhoden-basic.netlify.app/tagslist/。)
我试过将 dictsort
更改为 sort(attribute="posts2.length")
,以及其他可能有意义的排列,例如 sort(attribute="length")
,但没有任何效果。
我猜“长度”不是 post 本身的属性。所以也许像 sort
这样的过滤器在这种情况下不起作用。
但是有没有办法根据 post 计数对这个列表进行排序?肯定有。我需要引入 lodash 之类的东西,还是 map
之类的 javascript 函数?
您也许可以使用 Eleventy custom collections 来做您想做的事。我们可以使用.eleventy.js
文件中的Javascript统计每个标签中post的个数,然后按照post的个数对数据进行排序。
因为 Eleventy 似乎没有给我们预先分组的标签对象和 posts,所以我们自己做。这确实意味着,如果您将重复标签放在一个 post 上,它将被计算两次。可以对标签进行重复数据删除,但如果你小心的话,这应该不是问题。
// .eleventy.js
module.exports = function (eleventyConfig) {
// ...
// addCollection receives the new collection's name and a
// callback that can return any arbitrary data (since v0.5.3)
eleventyConfig.addCollection('bySize', (collectionApi) => {
// see https://www.11ty.dev/docs/collections/#getall()
const allPosts = collectionApi.getAll()
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
const countPostsByTag = new Map()
allPosts.forEach((post) => {
// short circuit eval sets tags to an empty array if there are no tags set
const tags = post.data.tags || []
tags.forEach((tag) => {
const count = countPostsByTag.get(tag) || 0
countPostsByTag.set(tag, count + 1)
})
})
// Maps are iterators so we spread it into an array to sort
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
const sortedArray = [...countPostsByTag].sort((a, b) => b[1] - a[1])
// this function returns an array of [tag, count] pairs sorted by count
// [['bonfires', 4], ['books', 3], ['boats', 2], ...]
return sortedArray
})
})
return {
// ...
}
}
然后我们可以在 Nunjucks 中使用这些数据 collections.bySize
。
<section id="tags-number-of-posts">
{# we can still destructure the tag name and count even though it's an array #}
{% for tag, count in collections.bySize %}
{% set tagUrl %}/tags/{{ tag | slug }}/{% endset %}
<a href="{{ tagUrl | url }}">{{ tag }} ({{ count }})</a><br/>
{% endfor %}
</section>
如果您需要在集合对象中包含 post 的数组,而不仅仅是 post 的数量,也可以修改 JavaScript 来执行所以。