2025-03-19
前端
00

目录

通常用法
改良方案
最终呈现

使用Markdown-It插件实现代码块高亮、代码块信息标识、代码复制等功能。

众所周知,markdown-it是用于md文本转html的工具包,其在markdown文档解析显示中非常之常用。

通常用法

通常情况下,它的标准用法应当是:

ts
import markdownit from "markdown-it"; const md = markdownit({html: true, breaks: true}); const MdText = () => { return ( <div dangerouslySetInnerHTML={{ __html: md.render(item.content), }} className={'markdown-body'} /> ) }

然而,其渲染的行内代码和代码块,使用的是<code>标签和<pre>标签。无法有辨识度地识别对应的代码区域、代码高亮,并感知语言类型。

image.png

改良方案

markdownit解决代码高亮的方式是使用插件markdown-it-highlightjs。其实也可以直接使用hljs,效果应该相差不大,不过我这里依然使用markdown-it-highlightjs作为使用方法演示。

首先是对插件进行安装:

ts
yarn add markdown-it-highlightjs

由于官方使用的require方法引入,本着复制粘贴的原则,我们也使用importrequire混用的方式导入:

ts
const md = markdownit({html: true, breaks: true}) .use(require('markdown-it-highlightjs'), { // 启用行内代码解析 inline: true, // 启用代码块解析 code: true, // 如果代码没有标注,自动猜它的代码类型,建议关闭 auto: false, });

同时,由于markdownit它本身只会解析代码块,用户无法知道这个代码块用的什么代码(md本身就会在```后面标注语言类型),因此我想给代码块上方做出一个长条,并且在上面写出标注的代码类型。因此,我们可以在保留markdownit原生解析的情况下,重写我们的新的代码解析函数:

ts
// 保存markdownit原有的代码块解析 const defaultFence = md.renderer.rules.fence || function (tokens, idx, options, env, self) { return self.renderToken(tokens, idx, options); }; // 在解析器上修改,这里我添加代码语言类型展示 md.renderer.rules.fence = function (tokens, idx, options, env, self) { const token = tokens[idx]; const info = token.info ? token.info.trim() : ''; const langName = info.split(/\s+/g)[0]; let codeHtml = defaultFence(tokens, idx, options, env, self); // 在代码块上方添加显示语言的标签 const langLabel = `<div class="code-lang">${md.utils.escapeHtml(langName ? langName : 'text')}</div>`; codeHtml = langLabel + codeHtml; return `<div class="code-block">${codeHtml}</div>`; };

并且,我们还需要引入CSS。我们可以下载 highlight.js/src/styles 中的样例css,也可以下载下来后自己修改配色。总之,我们还需要导入它:

ts
import 'sample.css' from '@/css/path';

最终呈现

最后,我们的代码呈现就变成了:

ts
import markdownit from "markdown-it"; import 'sample.css' from '@/css/path'; const md = markdownit({html: true, breaks: true}) .use(require('markdown-it-highlightjs'), { // 启用行内代码解析 inline: true, // 启用代码块解析 code: true, // 如果代码没有标注,自动猜它的代码类型,建议关闭 auto: false, }); // 保存markdownit原有的代码块解析 const defaultFence = md.renderer.rules.fence || function (tokens, idx, options, env, self) { return self.renderToken(tokens, idx, options); }; // 在解析器上修改,这里我添加代码语言类型展示 md.renderer.rules.fence = function (tokens, idx, options, env, self) { const token = tokens[idx]; const info = token.info ? token.info.trim() : ''; const langName = info.split(/\s+/g)[0]; let codeHtml = defaultFence(tokens, idx, options, env, self); // 在代码块上方添加显示语言的标签 const langLabel = `<div class="code-lang">${md.utils.escapeHtml(langName ? langName : 'text')}</div>`; codeHtml = langLabel + codeHtml; return `<div class="code-block">${codeHtml}</div>`; }; const MdText = () => { return ( <div dangerouslySetInnerHTML={{ __html: md.render(item.content), }} className={'markdown-body'} /> ) }

其展现效果如下所示:

image.png

本文作者:Jeff Wu

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!