首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在下一个JS中解析MDX文件?

在下一个JS中解析MDX文件?
EN

Stack Overflow用户
提问于 2022-08-22 15:39:39
回答 3查看 253关注 0票数 1

我有一个.mdx文件,我要导入到带有下一个JS的页面中。我想要创建链接片段到页面上的每一个标题。

因此,如果我的默认减价输出是:

代码语言:javascript
复制
<h2>Title 1</h2>
<p>Text 1</p>
<h2>Title 2</h2>
<p>Text 2</p>

我需要把它改为:

代码语言:javascript
复制
<h2 id="heading-1">Title 1</h2>
<p>Text 1</p>
<h2 id="heading-2">Title 2</h2>
<p>Text 2</p>

我还需要知道标题的文本和ID,这样我就可以创建链接:

代码语言:javascript
复制
<a href="#heading-1">Title 1</a>
<a href="#heading-2">Title 2</a>

我可以手动完成,但我希望链接是自动生成的。还可以生成标题ID,并且不需要有友好的人名。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-08-22 16:22:59

向每个id添加一个h1

ids添加到标题中非常简单。您可以通过向您的components中添加一个MDXProvider支柱来做到这一点,您可以在其中指定如何对待每个元素:

代码语言:javascript
复制
<MDXRemote {...props.mdx} />

然后您可以指定您的h1组件应该有一个id集。如果您愿意,可以生成一个id,但是在本例中,我们只使用children作为id

代码语言:javascript
复制
const adjustedComponents = {
    h1: (props) => (
      <Heading id={props.children} as="h1" size="lg">
        {props.children}
      </Heading>
    ),
}

创建目录

将链接添加到每个标题中要复杂一些。为此,您可以使用类似remark备注-之类的东西,但不幸的是,这将限制您只能在 Markdown中显示目录,这可能不是您想要的。

为了更好地控制目录,我们必须解析内容并创建一个自定义的标题列表。

代码语言:javascript
复制
const headings = await getHeadings(content);

乔希·科莫想出了一种很好的方法来解析h2h3标题。如果您想继续使用h1标题,就必须修改它:

代码语言:javascript
复制
export async function getHeadings(source) {
  // Get each line individually, and filter out anything that
  // isn't a heading.
  const headingLines = source.split("\n").filter((line) => {
    return line.match(/^###*\s/);
  });

  // Transform the string '## Some text' into an object
  // with the shape '{ text: 'Some text', level: 2 }'
  return headingLines.map((raw) => {
    const text = raw.replace(/^###*\s/, "");
    // I only care about h2 and h3.
    // If I wanted more levels, I'd need to count the
    // number of #s.
    const level = raw.slice(0, 3) === "###" ? 3 : 2;

    return { text, level };
  });

  return headingLines;
}

使用从getStaticProps返回的数据,然后可以将标题数据传递给我们可以创建的组件:

代码语言:javascript
复制
<TableOfContents headings={props.headings} />
代码语言:javascript
复制
const TableOfContents = ({ headings }) => {
  return (
    <div>
      <Heading as="h3">Table of Contents:</Heading>
      {headings.map((heading) => {
        return (
          <a key={heading.text} href={`#${heading.text}`}>
            {heading.text}
          </a>
        );
      })}
    </div>
  );
};

注意,由于我们使用了标题的标题文本,所以我们可以很容易地使用相同的数据来设置链接:<a href={#${heading.text}}>.的href值。那样的话,所有的链接都会到达正确的位置。

全例

下面是一个完整的工作示例 on CodeSandbox:

票数 3
EN

Stack Overflow用户

发布于 2022-08-22 16:10:00

当然,您可以尝试使用“真实”解析器来完成此操作。考虑到你的用例,我觉得这太过分了。如果你想试一试,我推荐备注-mdx

或者,我只使用一个简单的正则表达式系统。我不会为你编写代码,但我会这样做:

代码语言:javascript
复制
headings = []
while(find(header regex) is not -1):
    index = find(header regex)
    replace(index, <h2, <h2 id="header-{headings.length}")
    headings.push(
        {
            id: "header-{headings.length}",
            text: evaluate(header regex).capture_group[0]
        }
    )

为了让regex找到这些头文件,我会尝试类似于这个堆栈溢出线程的内容。我还建议您阅读捕获组这里

我希望这是足够详细的。如果你还有其他问题,只需在这个问题下发表评论。

票数 1
EN

Stack Overflow用户

发布于 2022-08-26 15:31:47

在回答的基础上,我找到了一个我比较喜欢的解决方案。MDX允许HTML,所以我正在检测标记中的标题,并用基于索引的ID替换它。这有一个优点,您可以使用相同的文本有多个标题。

我正在向页面传递一系列标题。使用数组中的索引,我可以创建所需的链接片段。

代码语言:javascript
复制
import {GetStaticProps} from "next";
import path from "path";
import fs from "fs";
import matter from "gray-matter";
import {serialize} from "next-mdx-remote/serialize";

export async function getStaticProps(props: GetStaticProps) {
    const root = process.cwd();
    const folderPath = path.join(root, "pages/my-post");
    const filePath = path.join(folderPath, "my-post-content.mdx");
    const fawFile = fs.readFileSync(filePath);
    const { content } = matter(fawFile);

    let headingsI = 0;
    const headings: string[] = [];

    const contentModified = content
        .split("\n")
        .map((item) => {
            if (item.startsWith("### ")) {
                headingsI++;
                const headingText = item.replace("### ", "");
                headings.push(headingText);
                return `<h3 id="h3-${headingsI}">${headingText}</h3>\n`;
            }
            return item;
        })
        .join("\n");

    const mdxSource = await serialize(contentModified);

    return {
        props: {
            content: mdxSource,
            headings,
        },
    };
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73447710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档