markdown toc php,使用 marked 解析 Markdown 并生成目录导航 TOC 功能

该博客介绍了如何使用marked库和自定义renderer来解析Markdown,并利用Tocify组件生成目录树。通过renderer.heading方法,根据标题级别创建锚点,并构建TOC目录结构。最后展示如何结合Markdown内容和目录进行渲染。
摘要由CSDN通过智能技术生成

1、新建一个 tocify.tsx

import React from 'react';

import { Anchor } from 'antd';

import { last } from 'lodash';

const { Link } = Anchor;

export interface TocItem {

anchor: string;

level: number;

text: string;

children?: TocItem[];

}

export type TocItems = TocItem[]; // TOC目录树结构

export default class Tocify {

anchors: string[];

tocItems: TocItems = [];

constructor() {

this.anchors = [];

this.tocItems = [];

}

add(text: string, level: number, id: string = '') {

const count = this.anchors.filter(anchor => anchor === text).length;

const anchor = id || (count ? `${text}${count}` : text);

this.anchors.push(anchor);

const item = { anchor, level, text };

const items = this.tocItems;

if (items.length === 0) { // 第一个 item 直接 push

items.push(item);

} else {

let lastItem = last(items) as TocItem; // 最后一个 item

if (item.level > lastItem.level) { // item 是 lastItem 的 children

for (let i = lastItem.level + 1; i <= 6; i++) {

const { children } = lastItem;

if (!children) { // 如果 children 不存在

lastItem.children = [item];

break;

}

lastItem = last(children) as TocItem; // 重置 lastItem 为 children 的最后一个 item

if (item.level <= lastItem.level) { // item level 小于或等于 lastItem level 都视为与 children 同级

children.push(item);

break;

}

}

} else { // 置于最顶级

items.push(item);

}

}

return anchor;

}

reset = () => {

this.tocItems = [];

this.anchors = [];

};

renderToc(items: TocItem[]) { // 递归 render

return items.map(item => (

{item.children && this.renderToc(item.children)}

));

}

render() {

return (

{this.renderToc(this.tocItems)}

);

}

}

2、重写 renderer.heading

import marked from 'marked';

import Tocify from './tocify';

const tocify = new Tocify();

const renderer = new marked.Renderer();

renderer.heading = function(text, level, raw) {

const anchor = tocify.add(text, level);

return `${text}\n`;

};

marked.setOptions({ renderer });

3、最后代码实现

(props) => (

className="content"

dangerouslySetInnerHTML={{ __html: marked(props.content) }}

/>

{tocify && tocify.render()}

)

markdown 解析的时候会通过 rendeer.heading 解析标题,然后我们在 rendeer.heading 使用 tocify.add 来生成目录树(根据 level)并返回一个锚点,rendeer.heading 再根据这个锚点生成一个a链接,最后我们调用 tocify.render() 渲染就可以了

本作品采用《CC 协议》,转载必须注明作者和本文链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值