• 魔改editormd组件,优化ToC渲染效果


    前言#

    我的StarBlog博客目前使用 editor.md 组件在前端渲染markdown文章,但这个组件自动生成的ToC(内容目录)不是很美观,我之前魔改过一个树形组件 BootStrap-TreeView,所以就想要用这个树形组件来展示ToC。

    原本的效果是这样的

    我魔改完的效果

    先分析一波#

    首先看一下 editor.md 这个组件如何渲染 markdown,根据官方的例子

    先写个 textarea 把 markdown 放进去

    <div id="post-markdown-content" class="post-content">
        <textarea style="display:none;">@Model.Contenttextarea>
    div>
    

    还要一个 div 来放目录

    <div id="post-toc-container">div>
    

    然后用js调用它的渲染方法

    let editorMdView = editormd.markdownToHTML("post-markdown-content", {
        htmlDecode: true,
        tocm: true,    // Using [TOCM]
        tocContainer: "#toc-container", // 自定义 ToC 容器层
        emoji: true,
        taskList: true,
        tex: true,  // 默认不解析
        flowChart: true,  // 默认不解析
        sequenceDiagram: true,  // 默认不解析
    });
    

    这样文章内容和目录就都出来了

    我一开始想的是,既然它可以渲染出来目录,那一定是有一个目录树的结构可以用

    结果在控制台 console.log 半天都没看到这个树结构

    editormd.markdownToHTML 方法返回的数据就单纯是一个 div 元素的对象……

    开始折腾#

    无语,没办法我只能去看源码

    整个组件的源码都在一个 js 文件内,幸好可读性还行~

    直接找到 markdownToHTML 方法的定义,在3885行开始,然后找到里面有个变量 markdownToC ,应该就是我们要的了,打印一下看看,大致结构如下

    [
        {"text": "Node1", "slug": "node1", "level": 2},
        {"text": "Django-Dev", "slug": "django-dev", "level": 3},
        {"text": "Java-Dev", "slug": "java-dev", "level": 3},
        {"text": "Spring-Dev", "slug": "spring-dev", "level": 3}
    ]
    

    不是树结构,就是个array

    就是简单的对整个markdown文档进行遍历,level 字段根据标题类型来确定,也就是 # 的数量。

    而我之前魔改的 Bootstrap-Treeview 组件需要传入一个树结构的对象进行渲染,所以我需要进一步处理。

    处理树结构#

    一开始我头铁,直接把 editor.md 生成的那坨东西丢进递归里面

    结果没搞出来

    后面换了思路,先把这个 array 改一下,给每个 item 加上 id 和 pid,这样再来递归生成树就好处理得多了~

    先定义节点对象,这个就是 Bootstrap-Treeview 需要用的数据结构

    class TocNode {
        constructor(text, href, tags, nodes) {
            this.text = text
            this.href = href
            this.tags = tags
            this.nodes = nodes
        }
    }
    

    然后来把 markdownToC 那坨东西遍历一遍,顶层节点的 pid 设置成 -1,每个节点从 0 开始按顺序赋值 id,然后每个节点往前面找 level 少 1 的节点,找到就是父节点,设置 pid ,完事~

    let toc = markdownToC
    for (let i = 0; i < toc.length; i++) {
        let item = toc[i]
        item.id = i
        item.pid = -1
        for (let j = i; j >= 0; j--) {
            let preItem = toc[j]
            if (item.level === preItem.level + 1) {
                item.pid = j
                break
            }
        }
    }
    

    生成树结构,很简单不多说了

    function getNodes(pid = -1) {
        let nodes = toc.filter(item => item.pid === pid)
        if (nodes.length === 0) return null
        return nodes.map(item => new TocNode(item.text, `#${item.text}`, null, getNodes(item.id)))
    }
    

    搞定~

    魔改#

    然后就是根据这个思路,fork了一份代码进行魔改。

    原版是在 markdownToHTML 方法执行完直接返回一个 div 元素,我则是在返回的 div 元素上添加了两个属性,然后再返回 div:

    div.markdownToc = markdownToC
    div.markdownTocTree = editormd.tocListToTree(markdownToC)
    return div
    

    这样在使用的时候就可以方便的将 Bootstrap-Treeview 组件整合进来了。

    用法#

    先安装我发布的NPM包

    // 魔改的 editor.md 组件
    npm i editor.md-ext
    // 魔改的树形列表组件
    npm i bootstrap5-treeview
    

    页面上引入 CSS

    <link rel="stylesheet" href="~/lib/editormd/css/editormd.preview.css">
    

    引入 JS

    
    <script src="~/lib/jquery/dist/jquery.min.js">script>
    
    
    <script src="~/js/bootstrap-treeview.js">script>
    
    
    <script src="~/lib/editormd/lib/marked.min.js">script>
    <script src="~/lib/editormd/lib/prettify.min.js">script>
    <script src="~/lib/editormd/lib/raphael.min.js">script>
    <script src="~/lib/editormd/lib/underscore.min.js">script>
    <script src="~/lib/editormd/lib/sequence-diagram.min.js">script>
    <script src="~/lib/editormd/lib/flowchart.min.js">script>
    <script src="~/lib/editormd/lib/jquery.flowchart.min.js">script>
    <script src="~/lib/editormd/editormd.js">script>
    

    准备一个 div 作为目录容器

    <div id="post-toc-container">div>
    

    准备一个 div 存放文章内容,把 Markdown 内容放进这个 textarea 里面。

    <div id="post-markdown-content" class="post-content">
        <textarea style="display:none;">@Model.Contenttextarea>
    div>
    

    写一段 JS 代码来启用渲染

    $(function () {
        // 渲染文章
        let editorMdView = editormd.markdownToHTML("post-markdown-content", {
            htmlDecode: true,
            tocm: true,    // Using [TOCM]
            emoji: true,
            taskList: true,
            tex: true,  // 默认不解析
            flowChart: true,  // 默认不解析
            sequenceDiagram: true,  // 默认不解析
        });
    
        // 渲染目录
        $('#post-toc-container').treeview({
            data: editorMdView.markdownTocTree,
            levels: 2,
            enableLinks: true,
            highlightSelected: false,
            showTags: true,
        })
    })
    

    关于树形列表组件的用法可以看我的 GitHub :https://github.com/Deali-Axy/bootstrap5-treeview

    相关地址#

    GitHub:https://github.com/Deali-Axy/editor.md-ext

    NPM:https://www.npmjs.com/package/editor.md-ext

  • 相关阅读:
    redis数据库
    源码级深度理解 Java SPI
    java面向对象
    MySQL用户管理
    基于pion生态的SFU实时音视频发布服务(二)
    Oracle数据库:创建和删除视图view,简单和复杂视图,内建视图,topN分析,oracle分页查询
    社区驱动开发:技术选型的另类浅析
    elementui中el-select和el-tree实现下拉树形多选功能
    TPTU: Task Planning and Tool Usage of Large Language Model-based AI Agents
    leetcodetop100(29) K 个一组翻转链表
  • 原文地址:https://www.cnblogs.com/deali/p/16809918.html