目录
本文收录在《如何开发一个自己的笔记软件》系列中,该系列源码均可在 Blossom 笔记软件 仓库中查看。仓库地址:
为笔记拓展 Katex 和 Mermaid
在上一篇中,主要介绍了如何使用 Markedjs 来解析渲染 Markdown 内容。本篇将介绍如何在其中拓展对 katex 和 mermaid 的支持。
一、katex
安装
源码地址 Katex 源码地址
官方文档 Katex 官方文档
安装依赖
bash
npm install katex
使用
typescript
import katex from 'katex'
import 'katex/dist/katex.min.css'
// 最基础的用法,传入 katex 语法字符串,返回 html
// 更多配置项:https://katex.org/docs/options
const html = katex.renderToString(katexStr, {
// 是否抛出异常,你可以指定抛出然后自己捕获异常,并处理对应异常信息
throwOnError: true,
// 如果为false,则渲染结果是内联模式
displayMode: true,
// 渲染为 html
output: 'html'
})
在 Markedjs 中的示例
在 Markedjs 中,使用行内代码块和多行代码块来支持 katex 语法。
行内公式
行内公式使用行内代码块进行拓展,重写了codespan
渲染函数。
typescript
const renderer = {
codespan(src: string): string {
let arr = src.match(/^\$+([^\$\n]+?)\$+/)
if (arr != null && arr.length > 0) {
try {
return katex.renderToString(arr[1], {
throwOnError: true,
output: 'html'
})
} catch (error) {
console.error(error)
return `<div class='bl-preview-analysis-fail-inline'>
Katex 语法解析失败! 你可以尝试前往<a href='https://katex.org/#demo' target='_blank'> Katex 官网</a> 来校验你的公式。
</div>`
}
}
return `<code>${src}</code>`
}
}
marked.use({ renderer: renderer })
// 输入 katex 语法,将解析为行内公式
marked.parse('`$E=mc^2$`', { async: true }).then((htmlResult: string) => {
html = htmlResult
})
多行公式
多行公式使用多行代码块进行拓展,重写了code
渲染函数。
typescript
import katex from 'katex'
import 'katex/dist/katex.min.css'
const renderer = {
code(code: string, language: string | undefined, _isEscaped: boolean): string {
// 判断是否为 katex 代码块
if (language === 'katex') {
try {
return katex.renderToString(escape2Html(code), {
throwOnError: true,
displayMode: true,
output: 'html'
})
} catch (error) {
console.error(error)
return `<div class='bl-preview-analysis-fail-block'>
<div class="fail-title">Katex 语法解析失败!</div><br/>
${error}<br/><br/>
你可以尝试前往 Katex 官网来校验你的公式, 或者查看<a href='https://katex.org/#demo' target='_blank'>相关文档</a>
</div>`
}
}
}
}
marked.use({ renderer: renderer })
// 输入
// ```katex
// ```
// 将解析为多行公式
marked.parse('```katex\n$E=mc^2\n```', { async: true }).then((htmlResult: string) => {
html = htmlResult
})
二、 Mermaid
安装
源码地址 Mermaid 源码地址
官方文档 Mermaid 官方文档
安装依赖
bash
npm install mermaid
使用
Mermaid 提供了多种用法,本文只介绍调用API的方式。
Mermaid 的逻辑是,你需要先创建一个存放图表的容器元素,例如一个DIV,然后为元素指定一个ID。接着将这个 ID 和 mermaid 语法的内容一起传给mermaid.render(id,内容)
函数,在解析完成之后,会从页面中找到指定 ID 的 dom 元素,然后将渲染好的 SVG 内容设置到元素内部document.getElementById(ID).innerHtml
。
typescript
import mermaid from 'mermaid'
mermaid.initialize({ startOnLoad: false });
/**
* 绘制图标
*/
const drawDiagram = async () => {
// 图表内容
const graphDefinition = 'graph TB\na-->b';
// 获取渲染后的 svg
const { svg } = await mermaid.render('targetId', graphDefinition);
// 获取要放置的容器元素
element = document.getElementById('targetId')
element.innerHTML = svg;
};
await drawDiagram();
你还可以指定 Mermaid 的主题样式,样式包含:
default
:默认主题neutral
:适合黑白主题,比如打印时dark
:夜间模式forest
:绿色主体base
:设置为该主体,可以对样式进行定制
typescript
import mermaid from 'mermaid'
mermaid.initialize({
theme: 'base',
startOnLoad: false,
securityLevel: 'loose',
// 自定义样式
// https://mermaid.js.org/config/theming.html#theme-variables
'themeVariables': {
'fontFamily': 'inherit',
// 主要配色
'primaryColor': '#cfbef1',
'primaryTextColor': '#606266',
'primaryBorderColor': '#8143FF',
// 第二颜色
'secondaryColor': '#efc75e',
'secondaryTextColor': '#606266',
// 第三颜色
'tertiaryColor': '#C4DFFF',
'tertiaryTextColor': '#606266',
// 连线的颜色
'lineColor': '#A0A0A0',
}
});
在 Markedjs 中的示例
在 Markedjs 中,使用多行代码块进行拓展,并且进行了语法校验,用来在编写错误时进行提示
typescript
import mermaid from 'mermaid'
const renderer = {
code(code: string, language: string | undefined, _isEscaped: boolean): string {
// 创建一个ID
const eleid = 'mermaid-' + Date.now() + '-' + Math.round(Math.random() * 1000)
const escape = escape2Html(code) as string
// 解析内容,判断 mermaid 的语法是否合法
mermaid.parse(escape).then(syntax => {
let canSyntax: boolean | void = syntax
if (canSyntax) {
// 如果是合法内容, 则进行解析
mermaid.render(eleid + '-svg', escape).then((resp) => {
// 获取解析好的 svg
const { svg } = resp
let element = document.getElementById(eleid)
element!.innerHTML = svg
})
}
})
// 语法错误时,可以指定渲染的内容
.catch(error => {
console.error('mermaid 格式校验失败:错误信息如下:\n', error)
let html = `<div class='bl-preview-analysis-fail-block'>
<div class="fail-title">Mermaid 语法解析失败!</div><br/>
${error}<br/><br/>
你可以尝试前往 Mermaid 官网来校验你的内容, 或者查看<a href='https://mermaid.live/edit' target='_blank'>相关文档</a>
</div>`
let element = document.getElementById(eleid)
element!.innerHTML = html
})
return `<p id="${eleid}">${eleid}</p>`
}
}
marked.use({ renderer: renderer })
// 输入
// ```katex
// ```
// 将解析为多行公式
marked.parse('```katex\n$E=mc^2\n```', { async: true }).then((htmlResult: string) => {
html = htmlResult
})