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

11ty技术问询:如何将嵌套数据合并为单个集合项?

实现Eleventy多章节博客内容合并方案

针对你提出的「拆分博客章节文件、同目录存放资源」需求,以下是两种无需每个文章单独添加数据文件的实现方案:


方案一:全局eleventyComputed自动合并章节

通过全局数据文件自动读取当前文章的主文件与章节文件,合并为完整内容。

步骤1:创建内容读取工具

在项目根目录的_data文件夹下新建postContent.js:

const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');

// 返回一个函数,接受文章文件路径,返回合并后的Markdown内容
module.exports = function() {
  return function(postInputPath) {
    const postDir = path.dirname(postInputPath);
    let contentParts = [];

    // 读取主文件index.md
    const mainFile = path.join(postDir, 'index.md');
    if (fs.existsSync(mainFile)) {
      const { content } = matter(fs.readFileSync(mainFile, 'utf8'));
      contentParts.push(content);
    }

    // 读取sections目录下的章节文件,按数字前缀排序
    const sectionsDir = path.join(postDir, 'sections');
    if (fs.existsSync(sectionsDir)) {
      const sectionFiles = fs.readdirSync(sectionsDir)
        .filter(file => file.endsWith('.md'))
        .sort((a, b) => parseInt(a.split('.')[0]) - parseInt(b.split('.')[0]));

      sectionFiles.forEach(file => {
        const { content } = matter(fs.readFileSync(path.join(sectionsDir, file), 'utf8'));
        contentParts.push(content);
      });
    }

    return contentParts.join('\n\n');
  };
};

步骤2:全局配置eleventyComputed

在_data下新建eleventyComputed.js,自动为所有文章合并内容:

const getPostContent = require('./postContent.js')();

module.exports = {
  content: function(data) {
    // 仅处理posts目录下的index.md文件
    if (data.page.inputPath.includes('/posts/') && data.page.fileSlug === 'index') {
      return getPostContent(data.page.inputPath);
    }
    // 非文章文件保留原内容
    return data.content;
  }
};

步骤3:配置资源复制

在.eleventy.js中添加资源目录的自动复制,确保图片能正确输出:

module.exports = function(eleventyConfig) {
  eleventyConfig.addPassthroughCopy('./posts/**/assets');
  // 其他配置...
};

方案二:自定义集合合并章节

通过创建自定义集合,直接生成包含合并内容的文章集合,适合需要统一管理文章数据的场景。

在.eleventy.js中添加集合配置:

const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');

module.exports = function(eleventyConfig) {
  eleventyConfig.addCollection('mergedPosts', function(collectionApi) {
    // 获取所有posts目录下的index.md文件
    const rawPosts = collectionApi.getFilteredByGlob('./posts/**/index.md');

    return rawPosts.map(post => {
      const postDir = path.dirname(post.inputPath);
      let mergedContent = post.templateContent;

      // 读取并合并章节文件
      const sectionsDir = path.join(postDir, 'sections');
      if (fs.existsSync(sectionsDir)) {
        const sectionFiles = fs.readdirSync(sectionsDir)
          .filter(file => file.endsWith('.md'))
          .sort((a, b) => parseInt(a.split('.')[0]) - parseInt(b.split('.')[0]));

        sectionFiles.forEach(file => {
          const { content } = matter(fs.readFileSync(path.join(sectionsDir, file), 'utf8'));
          mergedContent += '\n\n' + content;
        });
      }

      // 返回包含合并内容的文章对象
      return {
        ...post.data,
        content: mergedContent,
        slug: post.data.slug || `/posts/${path.basename(postDir)}`
      };
    });
  });

  // 复制资源目录
  eleventyConfig.addPassthroughCopy('./posts/**/assets');
};

之后在模板中直接使用collections.mergedPosts即可获取合并后的文章数据:

{% for post in collections.mergedPosts %}
  <article>
    <h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
    {{ post.content | safe }}
  </article>
{% endfor %}

关键细节说明

  1. 图片路径:章节文件中直接使用相对路径引用图片即可,例如![章节图片](./assets/post1-section1-img01.jpg),资源会随文章目录一起被复制到输出目录。
  2. 章节排序:通过文件名前缀数字(01.md、02.md)确保章节顺序正确,避免字符串排序导致的顺序混乱。
  3. 依赖安装:两种方案都需要安装gray-matter解析Markdown的Front Matter:
    npm install gray-matter --save-dev
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 03:27:32