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

JavaScript递归生成页面面包屑扁平数组的问题修复

问题背景

我正在通过Contentful API处理数据,搭建目标网站的结构。目前使用GraphQL API获取Contentful页面数据,但受API速率限制,查询引用关系和层级结构时无法设置过深的查询层级。

因此我选择查询pages内容类型,仅获取每个页面及其上一级父页面ID,计划在构建阶段(使用Eleventy构建站点)通过JavaScript递归逻辑拼接出完整的页面层级结构。

我需要一个可生成面包屑数组的函数:理想状态下传入单个页面ID,函数即可遍历数据集,依次获取父页面、父页面的父页面详情,直到无上级父页面为止。

当前实现

我当前编写了两个拆分函数,不确定是否为最优实现:

/**
   * 接收页面ID,在contentfulPages数组(Contentful GraphQL查询返回结果)中查找对应页面
   * 返回包含页面ID、slug(用于生成URL)、title(用于展示可读文本)、parentPageId的对象,供后续获取父页面信息使用
   */
  function getParentPage(pageId) {
    const { id, slug, title, parentPageId } = contentfulPages.find(
      (page) => page.id === pageId
    );
    return { id, slug, title, parentPageId };
  }

  /**
   * 接收页面ID,调用getParentPage获取第一层父页面详情。如果存在更高层级父页面,
   * 则使用新找到的父页面ID递归调用自身,将返回对象推入breadcrumbArray。
   * 由于函数直接返回面包屑数组,当前实现每次递归都会生成一层嵌套数组,而非同层级对象
   */
  function getBreadcrumb(pageId) {
    let breadcrumbArray = [];
    const { id, slug, title, parentPageId } = getParentPage(pageId);
    breadcrumbArray.push({ id, slug, title, parentPageId });
    if (parentPageId) {
      breadcrumbArray.push(getBreadcrumb(parentPageId));
    }
    return breadcrumbArray;
  }
问题描述

当前代码返回多层嵌套数组,预期输出为由页面对象组成的扁平数组,三层深度页面的预期输出与实际输出对比如下:

// 预期输出
[
  {
    id: 'page-3',
    slug: 'courses',
    title: 'Courses',
    parentPageId: 'page-2'
  },
  {
    id: 'page-2',
    slug: 'training',
    title: 'Training',
    parentPageId: 'page-1'
  },
  {
    id: 'page-1',
    slug: 'services',
    title: 'Services',
    parentPageId: false
  },
]


// 实际输出
[
  {
    id: 'page-3',
    slug: 'courses',
    title: 'Courses',
    parentPageId: 'page-2'
  },
  [
    {
      id: 'page-2',
      slug: 'training',
      title: 'Training',
      parentPageId: 'page-1'
    },
    [ 
      {
        id: 'page-1',
        slug: 'services',
        title: 'Services',
        parentPageId: false
      },
    ]
  ]
]
修复方案

嵌套问题的根源是递归调用getBreadcrumb的返回值本身是数组,直接用push插入会将整个数组作为单个元素存入当前数组,最终形成多层嵌套结构。使用展开运算符将递归返回的数组元素逐个合并到当前数组,即可得到扁平结构。

修改后的getBreadcrumb函数如下:

function getBreadcrumb(pageId) {
  const currentPage = getParentPage(pageId);
  // 无上级父页面时终止递归,返回仅包含当前页面的数组
  if (!currentPage.parentPageId) {
    return [currentPage];
  }
  // 合并当前页面与父级面包屑结果,保持当前页在前、根页在后的顺序
  return [currentPage, ...getBreadcrumb(currentPage.parentPageId)];
}

补充:常规面包屑导航需要按「根页面 -> 子页面 -> 当前页」的顺序展示,只需要调整返回顺序为return [...getBreadcrumb(currentPage.parentPageId), currentPage]即可。

建议给getParentPage增加容错逻辑,避免传入不存在的页面ID时解构报错:

function getParentPage(pageId) {
  const targetPage = contentfulPages.find(page => page.id === pageId);
  // 找不到对应页面时返回默认值,可根据业务需求调整为抛出明确错误
  if (!targetPage) {
    return { id: null, slug: '', title: '', parentPageId: false };
  }
  const { id, slug, title, parentPageId } = targetPage;
  return { id, slug, title, parentPageId };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 21:30:56