如何在 Eleventy 中创建标签集合和类别集合

How to create a Tags collection and a Categories collection in Eleventy

我的 .eleventy.js 文件中有以下两段代码

    // Tags
    eleventyConfig.addCollection('tagList', collection => {
        const tagsSet = new Set();
        collection.getAll().forEach(item => {
            if (!item.data.tags) return;
            item.data.tags.filter(tag => !['posts', 'all'].includes(tag)).forEach(tag => tagsSet.add(tag));
        });
        return Array.from(tagsSet).sort();
    });

    // Categories
    eleventyConfig.addCollection('categoryList', collection => {
        let catSet = new Set();
        collection.getAll().forEach(item => {
            if (!item.data.categories) return;
            item.data.categories.filter(cat => !['posts', 'all'].includes(cat)).forEach(cat => catSet.add(cat));
        });
        return Array.from(catSet).sort();
    });

在我的帖子里我有

---
layout: post
title: 'Whatever'
date: '2021-10-12'
permalink: '{{ title | slug }}/index.html'
categories:
    - code
tags:
    - javascript
    - angular
---

我正在使用这样的模板为每个标签自动生成页面(以及类似的类别页面)。

---
layout: page
eleventyComputed:
    title: All posts tagged '{{ tag }}'
    permalink: /tags/{{ tag }}/
pagination:
    data: collections
    size: 1
    alias: tag
    filter:
        - all
        - nav
        - post
        - posts
        - tagList
    addAllPagesToCollections: true
permalink: /tags/{{ tag }}/
headerButton:
    url: '/blog/'
    text: All posts
---

<ul class="unstyled">
    {%- for post in collections[tag].reverse() -%}
    {%- if not post.data.draft -%}
    <li>{% include 'post-listing.njk' %}</li>
    {%- endif -%}
    {%- endfor -%}
</ul>

对于标签,一切正常。我生成了正确的页面,即 /tags/javascript 但对于类别,它根据标签而不是类别生成页面。所以我最终得到的不是 /categories/code /categories/javascript

我假设问题出在我的 eleventyConfig.addCollection('categoryList') 函数上,但我不知道为什么。

您的问题可能出在模板的分页中。您在 collections object 上分页,这是一个对象映射标签(一个特殊的 11ty 前端属性)到具有该标签的页面。

由于您正在创建标签和类别列表作为集合项,因此您需要对该集合进行分页。

---
# ...
pagination:
    data: collections.tagList # (or collections.categoryList)
    size: 1
    alias: tag
    # ...
---

这可能会造成问题,因为您正在访问模板中的帖子本身,因此您需要一种方法将 tag/category 映射回帖子列表。您可以通过将集合更改为 Object 而不是 Array.

来解决此问题
    // Tags
    eleventyConfig.addCollection('tagList', collection => {
        const tagsSet = {};
        collection.getAll().forEach(item => {
            if (!item.data.tags) return;
            item.data.tags.filter(
                tag => !['posts', 'all'].includes(tag)
            ).forEach(
                tag => {
                    if (!tagsSet[tag]) { tagsSet[tag] = []; }
                    tagsSet[tag].push(item)
                }
            );
        });
        return tagsSet;
    });

    // Categories
    eleventyConfig.addCollection('categoryList', collection => {
        let catSet = {};
        collection.getAll().forEach(item => {
            if (!item.data.categories) return;
            item.data.categories.filter(
                cat => !['posts', 'all'].includes(cat)
            ).forEach(
                cat => {
                    if (!catSet[cat]) { catSet[cat] = []; }
                    catSet[cat].push(item)
                }
            );
        });
        return catSet;
    });

现在,当您想要访问帖子时,您可以索引到 collections.tagList(或 collections.categoryList)。

{%- for post in collections.tagList[tag] | reverse -%}

您上面建议的一切都奏效了。我现在为标签和类别生成了单独的页面,非常感谢。

我现在遇到的问题是,在我的博客页面上,我以前有一个像这样输出的标签列表

<div class="tags tags--buttons">
  {%- for tag in collections.tagList -%}
    <a href="/tags/{{tag}}">{{tag}}</a>
  {%- endfor -%}
</div>

这不再输出任何内容,因为集合不再是数组。

我更新到

<div class="tags tags--buttons">
  {%- for tag, val in collections.tagList -%}
    <a href="/tags/{{tag}}">{{tag}}</a>
  {%- endfor -%}
</div>

这适用于标签,但不适用于集合(使用 collections.categoryList

此外,标签不再按字母顺序排列

有什么建议吗?

更新:

输出类别的代码是

    {%- for cat, val in collections.categoryList | dictsort -%}
        {%- if cat !== "posts" -%}
            <a href="/categories/{{cat}}">{{cat}}</a>
        {%- endif -%}
    {%- endfor -%}

这不会给出任何错误,但也没有输出。 如果我向其中添加 | dictsort,则会收到错误 Template render error: dictsort filter: val must be an object