在antd里面渲染MarkDown并且自定义一个锚点目录TOC(重点解决导航目录不跟随文档滚动的问题)
一、整体思路
由于有很多很长的文档需要渲染,我觉得用MarkDown的方式会比较适合管理,所以这两天测试了一下在antd里面集成MarkDown的渲染模块。
总体思路参考:
https://blog.csdn.net/Sakuraaaa_/article/details/128400497
感恩大佬的倾情付出。
-
- 使用react-markdown解析MarkDown
-
- 使用antd的Anchor锚点组件做一个类TOC的跳转目录
二、不说废话
1.完整代码
import React, {useState, useEffect, useRef} from 'react';
import Markdown from 'react-markdown';
import {getMarkDown} from "@/services/ant-design-pro/api";
import 'github-markdown-css';
import {Collapse, Anchor, BackTop, Col, Row} from "antd";
const { Link } = Anchor;
const { Panel } = Collapse;
import styles from './style.less';const App = ({markdownFileName}) => {const [mdContent, setMdContent] = useState('')const [at, setAt] = useState('')useEffect(() => {let ret = getMarkDown(markdownFileName)ret.then((res)=>{setMdContent(res)addAnchor()})}, []);const addAnchor = () => {const ele = document.getElementsByClassName('markdown-body')[0];let eid = 0;let ttitles = [];for (const e of ele.childNodes) {// if (e.nodeName === 'H1' || e.nodeName === 'H2' || e.nodeName === 'H3' || e.nodeName === 'H4' || e.nodeName === 'H5' || e.nodeName === 'H6') {if (e.nodeName === 'H2') {let a = document.createElement('a');a.setAttribute('id', 'h2_' + eid);a.setAttribute('class', 'anchor-title');a.setAttribute('href', '#' + eid);a.innerText = ' 'let title = {type: e.nodeName,id: eid,name: e.innerText};ttitles.push(title);e.appendChild(a);eid++;}}setAt((<AnchoronClick={handleClickFun}getContainer={()=>ele}>{ttitles.map(t => (<Link href={'#h2_' + t.id} title={t.name}/>))}</Anchor>))}const handleClickFun = (e, link) => {console.log('click')e.preventDefault();if (link.href) {// 找到锚点对应得的节点let element = document.getElementById(link.href);// 如果对应id的锚点存在,就跳滚动到锚点顶部element && element.scrollIntoView({ block: 'start', behavior: 'auto' });}}return (<div className="scrollable-container"><divclassName={styles.markdownnav}><Collapse defaultActiveKey={['1']} ghost><Panel header="章节目录" key="1">{at}</Panel></Collapse></div><MarkdownclassName='markdown-body'>{mdContent}</Markdown><BackTop/></div>)
}export default App
效果,由于手头上没有长的md,简单演示下。

代码很简单,主要和大家说说我遇到的几个问题。
二、难点?或者说要点
1.MarkDown自定义样式
import 'github-markdown-css';
引入这个风格后确实文档的样式有所美观,
但我还需要根据自己的要求修改几个风格,在引入的less中用global参数覆盖上面的样式就可以。原理可以看看我自定义dot那篇。
:global {.markdown-body h1 {//margin: .67em 0;font-weight: var(--base-text-weight-semibold, 600);padding-bottom: .3em;font-size: 2em;border-bottom: 1px solid var(--color-border-muted);margin: 0 auto;text-align: center;}.markdown-body p{text-indent: 2em; /*首行缩进*/}
}
2.导航目录生成
虽然我接触react时间也不短了,但是确实也没有精细的研究过react的渲染过程中几个回调的顺序问题。尤其是函数组件的资料更难找。
你看我这里的jsx里面,并没有直接把Anchor组件写在这里,而是写在了MarkDown渲染完成后的回调中。
setAt((<AnchoronClick={handleClickFun}getContainer={()=>ele}>{ttitles.map(t => (<Link href={'#h2_' + t.id} title={t.name}/>))}</Anchor>))
原因就是我这里需要设置getContainer的值,默认是获取window,那window铁定是不滚动的,还我们需要把MarkDown的elment给他挂上去。如果直接写需要用ref的方式获取,但是MarkDown组件没办法获取他的ref,我不知道怎么解决这个问题,所以讨巧的再useEffect里面来做目录组件的插入,因为这里Dom的渲染已经完成,我们可以通过document.getElementsByClassName来获取MarkDown的element。
3.导航目录随文档滚动问题
根据上面的S大佬的代码写,无论我怎么调整getContainer的容器都无法跟随文档滚动。
所实话这个也不是我第一次吐槽antd了,这个文档真的是简陋,不够这次我痛定思痛。
根据https://juejin.cn/post/7158430758070140942这位大佬的思路,测地落实了一下用webstrom的断点来调试源码的方法。终于搞清楚为啥没办法跟随文档滚动。
我们需要先明白一个点:Anchor的代码里面是怎么实现滚动监听的呢?
实现还挺粗暴的,对你传入的getContainer的容器进行滚动监听,当出现滚动事件的时候,检查容器中的所有跳转链接和顶部的距离,来设置激活的目录。
问题出在S大佬的代码中插入a链接的id上。

可以看到S大佬这里给id的前面加了个#,这个#在点击跳转的时候不会有问题,但是在滚动的时候就会出现问题。原因是这个地方进行了一个正则的过滤

这个正则主要的工作是过滤掉前面的#号

然而根据S大佬的id配置的是#开头的。所以就导致这里的id没办法找到对应的a标签,所以就没办法监听到他的滚动位置。
解决方案也很简单。
- 1.在设置跳转标签,也就是插入a标签的地方。a标签的id不能带前面的#
- 2.在Anchor的Link中需要带#
这样设置完就可以看到目录跟随文章滚动的效果了。
上面我说了我要吐槽antd的文档,因为这么重要的设置他甚至都没有给一个示例代码,一切都需要靠自己分析自己猜,很好奇这个东西他们自己到底用不用?还是和语雀一样外部一套内部一套,外部这个就做着玩的吧。
PS
1.webstrom 用Chrome 调试时遇到链接不上chrome的问题
报错信息:
Please ensure that the browser was started successfully with remote debugging port opened.
原因是:由于偷懒我还在使用2021.3版本的webstrom,所以无法链接上新版本的chrome。更新webstorm之后解决。
具体配置方法可以查看:
https://juejin.cn/post/7126550003585122334
2.如何在antd里面优雅的获取element
// 取值
const child = useRef()
<div className="scrollable-container" ref={child}>
</div>// 调用
child.current
然而,对于react-markdown的MarkDown并不行,会报错:

不过我没什么代码美学,我就直接用document.getElementsByClassName了,希望有研究的大佬可以教我一下。
相关文章:
在antd里面渲染MarkDown并且自定义一个锚点目录TOC(重点解决导航目录不跟随文档滚动的问题)
一、整体思路 由于有很多很长的文档需要渲染,我觉得用MarkDown的方式会比较适合管理,所以这两天测试了一下在antd里面集成MarkDown的渲染模块。 总体思路参考: https://blog.csdn.net/Sakuraaaa_/article/details/128400497 感恩大佬的倾情付…...
Linux MMC子系统 - 2.eMMC 5.1总线协议浅析
By: Ailson Jack Date: 2023.10.27 个人博客:http://www.only2fire.com/ 本文在我博客的地址是:http://www.only2fire.com/archives/161.html,排版更好,便于学习,也可以去我博客逛逛,兴许有你想要的内容呢。…...
时序预测 | Python实现ARIMA-LSTM自回归移动差分模型结合长短期记忆神经网络时间序列预测
时序预测 | Python实现ARIMA-LSTM自回归移动差分模型结合长短期记忆神经网络时间序列预测 目录 时序预测 | Python实现ARIMA-LSTM自回归移动差分模型结合长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 时序预测 | Python实现ARIMA-LSTM自…...
【Linux】部署单机OA项目及搭建spa前后端分离项目
目录 部署OA项目 编辑 搭建spa前后端分离项目 后端 前端 配置坏境变量 部署OA项目 在虚拟机中,将项目打包成war文件放置到tomcat根目录下的webapps文件目录下 再在主机数据库中连接数据库,并定义数据库名导入相关的表 继续进入tomcat目录下双击点…...
2023中国计算机大会:蚂蚁集团连发两支百万级科研基金
10月26日,中国计算机学会(CCF)主办的第二十届中国计算机大会(CNCC2023)在沈阳举行。在“CCF-蚂蚁科研基金及产学研合作交流活动”上,蚂蚁集团发布了2023年度“CCF-蚂蚁科研基金”绿色计算及隐私计算两支百万级专项基金,…...
Knife4j使用教程(三) -- 实体类的配置注解(@ApiModel与@ApiModelProperty 的 认识与使用)
目录 1. @ApiModel与@ApiModelProperty的区分 2. @ApiModel注解 3. @ApiModelProperty注解 3.1 value属性 3.2 name属性...
计算机网络【CN】IPV4报文格式
版本(4bit):IPV4/IPV6首部长度(4bit):标识首部的长度 单位是4B最小为:20B最大为:60(15*4)B总长度(16bit):整个数据报&…...
SQL server数据库单用户模式如何退出
根据网上的说法,用下面的方式尝试即可退出 进入ssms数据库管理软件执行下面的sql语句 -- 第一步执行USE [master] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO--建一个存储过程,断开所有用户连接。 create proc [dbo].[killspid] (dbn…...
QT mqtt 在子线程中使用
qtmqtt 在子线程中使用_qt在子线程里mqtt无法new-CSDN博客文章浏览阅读524次。解决问题:QMqttClient - connection not made from another thread在qt中使用多线的qtmqtt客户端发送接收数据_qt在子线程里mqtt无法newhttps://blog.csdn.net/qq_35708970/article/deta…...
Tomcat运维以及优化
Tomcat常用运维命令 # 查看版本/opt/data/app/tomcat-9.0.82/bin/catalina.sh version## 启动 /opt/data/app/tomcat-9.0.82/bin/startup.sh # 停止 /opt/data/app/tomcat-9.0.82/bin/shutdown.sh调整JVM 参数 方式1 vim /opt/data/app/tomcat-9.0.82/bin/catalina.sh # OS…...
C++设计模式_14_Facade门面模式
本篇介绍的Facade门面模式属于“接口隔离”模式的一种,以下进行详细介绍。 文章目录 1. “接口隔离”模式1. 1 典型模式 2. 系统间耦合的复杂度3. 动机(Motivation)4. 模式定义5. Facade门面模式的代码实现6. 结构7. 要点总结8. 其他参考 1. “接口隔离”模式 在组…...
正点原子嵌入式linux驱动开发——外置RTC芯片PCF8563
上一章学习了STM32MP1内置RTC外设,了解了Linux系统下RTC驱动框架。一般的应用场合使用SOC内置的RTC就可以了,而且成本也低,但是在一些对于时间精度要求比较高的场合,SOC内置的RTC就不适用了。这个时候需要根据自己的应用要求选择合…...
自动驾驶感知算法面经(20+)
原文链接: https://zhuanlan.zhihu.com/p/656952371 本人2022年4月和2023年7月两次跳槽找工作,面经总结在这里,希望可以帮到需要的朋友。 项目相关的问题主要和经历有关,参考性不大。 2023年7月 1. 文远知行 自动标注算法岗位 项目经历问…...
计算机操作系统重点概念整理-第二章 进程管理【期末复习|考研复习】
第二章 进程管理 【期末复习|考研复习】 计算机操作系统系列文章传送门: 第一章 计算机系统概述 第二章 进程管理 第三章 进程同步 第四章 内存管理 第五章 文件管理 第六章 输出输出I/O管理 文章目录 第二章 进程管理 【期末复习|考研复习】前言二、进程管理2.1进…...
如何学好C++?学习C和C++的技巧是什么?
如何学好C?学习C和C的技巧是什么? 你这三个问题,前两个都是意思是差不多的,那么怎么怎么学习C/C我来问答一下:最近很多小伙伴找我,说想要一些C资料,然后我根据自己从业十年经验,熬夜搞了几个通…...
leetcode_39 组合总和
1. 题意 给定一个数组,和一个目标值;求得所有数组中所有和为目标值的元素序列。 组合总数 2. 题解 回溯列举每一个可能的序列,注意去重。 2.1 我的解法 class Solution { public:void gen(vector<vector<int>> &ans,co…...
【登录安全测试】
登录安全测试是确保系统的用户身份验证机制和登录过程的安全性的重要步骤。以下是一些常见的登录安全测试方面的考虑: 账号密码验证:验证系统是否能有效地验证用户的账号和密码,包括对密码长度、复杂性和有效性的限制。测试应包括正常和异常…...
MySQL -- 数据类型
MySQL – 数据类型 文章目录 MySQL -- 数据类型一、数据类型1.数据类型分类2.数值类型2.1.tinyint2.2.bit2.3小数类型 3.字符串类型3.1.char3.2.varchar 4.时间和日期类型5.enum和set 一、数据类型 1.数据类型分类 2.数值类型 2.1.tinyint tinyint类型的数值范围是-128 ~ 127…...
Windows11搭建kafka-python环境
文章目录 安装软件javazookeeperkafka命令行调试环境python-kafka环境参数解释名词解释定义基础架构同步发送、异步发送消息队列的两种模式消费者与消费组幂等性文件清理策略kafka消费模式offset作用kafka消费顺序如何保证参考文献安装软件 java 下载jdk,配置环境变量JAVA_H…...
一篇了解springboot3请求参数种类及接口测试
SpringBoot3数据请求: 原始数据请求: //原始方式RequestMapping("/simpleParam")public String simpleParam(HttpServletRequest request){//获取请求参数String name request.getParameter("name");String age request.getParam…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
