使用Markdown-It插件实现代码块高亮、代码块信息标识、代码复制等功能。
众所周知,markdown-it是用于md文本转html的工具包,其在markdown文档解析显示中非常之常用。
通常情况下,它的标准用法应当是:
tsimport 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>
标签。无法有辨识度地识别对应的代码区域、代码高亮,并感知语言类型。
markdownit解决代码高亮的方式是使用插件markdown-it-highlightjs
。其实也可以直接使用hljs
,效果应该相差不大,不过我这里依然使用markdown-it-highlightjs
作为使用方法演示。
首先是对插件进行安装:
tsyarn add markdown-it-highlightjs
由于官方使用的require
方法引入,本着复制粘贴的原则,我们也使用import
和require
混用的方式导入:
tsconst 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,也可以下载下来后自己修改配色。总之,我们还需要导入它:
tsimport 'sample.css' from '@/css/path';
最后,我们的代码呈现就变成了:
tsimport 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'}
/>
)
}
其展现效果如下所示:
本文作者:Jeff Wu
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!