我有一个.mdx文件,我要导入到带有下一个JS的页面中。我想要创建链接片段到页面上的每一个标题。
因此,如果我的默认减价输出是:
<h2>Title 1</h2>
<p>Text 1</p>
<h2>Title 2</h2>
<p>Text 2</p>我需要把它改为:
<h2 id="heading-1">Title 1</h2>
<p>Text 1</p>
<h2 id="heading-2">Title 2</h2>
<p>Text 2</p>我还需要知道标题的文本和ID,这样我就可以创建链接:
<a href="#heading-1">Title 1</a>
<a href="#heading-2">Title 2</a>我可以手动完成,但我希望链接是自动生成的。还可以生成标题ID,并且不需要有友好的人名。
发布于 2022-08-22 16:22:59
向每个id添加一个h1
将ids添加到标题中非常简单。您可以通过向您的components中添加一个MDXProvider支柱来做到这一点,您可以在其中指定如何对待每个元素:
<MDXRemote {...props.mdx} />然后您可以指定您的h1组件应该有一个id集。如果您愿意,可以生成一个id,但是在本例中,我们只使用children作为id
const adjustedComponents = {
h1: (props) => (
<Heading id={props.children} as="h1" size="lg">
{props.children}
</Heading>
),
}创建目录
将链接添加到每个标题中要复杂一些。为此,您可以使用类似remark和备注-之类的东西,但不幸的是,这将限制您只能在 Markdown中显示目录,这可能不是您想要的。
为了更好地控制目录,我们必须解析内容并创建一个自定义的标题列表。
const headings = await getHeadings(content);乔希·科莫想出了一种很好的方法来解析h2和h3标题。如果您想继续使用h1标题,就必须修改它:
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返回的数据,然后可以将标题数据传递给我们可以创建的组件:
<TableOfContents headings={props.headings} />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:
发布于 2022-08-22 16:10:00
当然,您可以尝试使用“真实”解析器来完成此操作。考虑到你的用例,我觉得这太过分了。如果你想试一试,我推荐备注-mdx。
或者,我只使用一个简单的正则表达式系统。我不会为你编写代码,但我会这样做:
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找到这些头文件,我会尝试类似于这个堆栈溢出线程的内容。我还建议您阅读捕获组这里。
我希望这是足够详细的。如果你还有其他问题,只需在这个问题下发表评论。
发布于 2022-08-26 15:31:47
在回答的基础上,我找到了一个我比较喜欢的解决方案。MDX允许HTML,所以我正在检测标记中的标题,并用基于索引的ID替换它。这有一个优点,您可以使用相同的文本有多个标题。
我正在向页面传递一系列标题。使用数组中的索引,我可以创建所需的链接片段。
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,
},
};
}https://stackoverflow.com/questions/73447710
复制相似问题