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

如何从Strapi富文本字段生成目录

如何从Strapi富文本数据生成目录

实现思路

Strapi的富文本(BlocksContent)是由不同类型的块组成的数组,其中标题类块(heading1/heading2/heading3等)包含目录所需的核心信息。可以通过以下三步实现目录功能:

  1. 从富文本数据中提取所有标题节点
  2. 为每个标题块添加锚点ID
  3. 渲染可跳转的目录组件

完整代码实现

import { BlocksRenderer, type BlocksContent, type Block } from "@strapi/blocks-react-renderer";
import { useGetBlogsByIdQuery } from "./your-gql-queries-path"; // 替换为你的GraphQL查询路径

// 提取标题节点的工具函数
const extractHeadings = (content: BlocksContent) => {
  if (!content) return [];
  
  return content.reduce((acc, block: Block) => {
    // 筛选所有标题类型的块
    if (block.type.startsWith('heading')) {
      // 提取标题层级(如heading1对应层级1)
      const level = parseInt(block.type.replace('heading', ''), 10);
      // 拼接标题文本内容
      const text = block.children?.map(child => child.text).join('') || '';
      // 生成唯一锚点ID(文本slug化处理,避免特殊字符)
      const id = text.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
      
      acc.push({ id, text, level });
    }
    return acc;
  }, [] as Array<{ id: string; text: string; level: number }>);
};

const Blog = ({ slug }: { slug: string }) => {
  const { data } = useGetBlogsByIdQuery(slug);
  const content: BlocksContent = data?.data?.attributes?.content;
  // 提取标题生成目录数据
  const tocItems = extractHeadings(content);

  // 自定义标题块渲染器,添加锚点ID
  const renderBlock = (block: Block) => {
    if (block.type.startsWith('heading')) {
      const level = parseInt(block.type.replace('heading', ''), 10);
      const text = block.children?.map(child => child.text).join('') || '';
      const id = text.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
      
      // 根据层级渲染对应h1-h6标签并添加锚点ID
      const HeadingTag = `h${level}` as keyof JSX.IntrinsicElements;
      return <HeadingTag id={id}>{text}</HeadingTag>;
    }
    // 其他类型块使用默认渲染逻辑
    return null;
  };

  return (
    <div className="blog-container">
      {/* 渲染目录 */}
      {tocItems.length > 0 && (
        <div className="table-of-contents">
          <h3>目录</h3>
          <ul>
            {tocItems.map(item => (
              <li key={item.id} style={{ marginLeft: `${(item.level - 1) * 16}px` }}>
                <a href={`#${item.id}`}>{item.text}</a>
              </li>
            ))}
          </ul>
        </div>
      )}

      {/* 渲染富文本内容,使用自定义标题渲染器 */}
      <BlocksRenderer content={content} renderBlock={renderBlock} />
    </div>
  );
};

export default Blog;

关键细节说明

  • 标题提取:通过extractHeadings遍历富文本块数组,筛选标题块后提取文本、层级,并生成唯一锚点ID(slug化处理避免特殊字符冲突)。
  • 自定义标题渲染:借助BlocksRenderer的renderBlock属性,为每个标题标签添加对应id,实现锚点跳转的基础。
  • 目录样式:通过marginLeft根据标题层级设置缩进,模拟多级目录的视觉层级,可根据需求调整样式规则。

扩展优化建议

  • 若存在重复标题文本,可在生成ID时追加索引(如my-heading-1、my-heading-2)避免锚点重复。
  • 可添加滚动监听逻辑,高亮当前浏览位置对应的目录项。
  • 长文章场景下,可将目录固定在侧边,提升用户浏览体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:20:06