找回密码
 立即注册
首页 业界区 业界 使用Vditor将Markdown文档渲染成网页(Vite+JS+Vditor) ...

使用Vditor将Markdown文档渲染成网页(Vite+JS+Vditor)

蝓俟佐 2025-6-3 00:37:01
1. 引言

编写Markdown文档现在可以说是程序员的必备技能了,因为Markdown很好地实现了内容与排版分离,可以让程序员更专注于内容的创作。现在很多技术文档,博客发布甚至AI文字输出的内容都是以Markdown格式的形式输出的。那么,Markdown文档如何渲染成标准的Web网页呢?这就要借助于一些支持Markdown格式的编辑器组件了。开源的Markdown编辑器组件有不少,Vditor是笔者认为功能比较全的一款,在这里本文就通过Vditor来实现将一个Markdown文档渲染成网页的具体案例。
阅读本文可能需要的前置文章:《使用Vite创建一个动态网页的前端项目》。
2. 实现

使用VS Code打开Vite初始化的工程,并且准备一个Markdown文档(笔者这里用的是Vditor的说明文档),文件组织如下所示:
my-native-js-app
├── public
│   └── demo.md
├── src
│   ├── main.js
│   └── style.css
├── index.html
└── package.json
打开终端,输入如下指令,安装Vditor依赖包:
  1. npm install vditor --save
复制代码
2.1 基本配置

修改index.html中的内容:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.   <head>
  4.     <meta charset="UTF-8" />
  5.     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.     <title>Vite App</title>
  8.   </head>
  9.   <body>
  10.    
  11.       
  12.    
  13.    
  14.   </body>
  15. </html>
复制代码
其中,名称为md-content的元素就是用来显示Markdown文档的容器。接着是style.css:
  1. #app {
  2.   width: 800px;
  3.   margin: 0 auto;
  4. }
复制代码
也非常简单,就是限制了显示Markdown文档的宽度以及设置居中显示。对于一个文字为主的网页来说,文档的宽度不宜太宽,现代主流的文档网页的设计都是600~800px左右。
最后就是关键的实现主要功能代码main.js:
  1. import "./style.css";
  2. import "vditor/dist/index.css";
  3. import Vditor from "vditor";
  4. async function initMarkdown() {
  5.   try {
  6.     const response = await fetch("/demo.md");
  7.     if (!response.ok) {
  8.       throw new Error("网络无响应");
  9.     }
  10.     const demoMd = await response.text();
  11.     // 显示内容
  12.     Vditor.preview(document.getElementById("md-content"), demoMd, {
  13.       markdown: {
  14.         toc: false,
  15.         mark: true, //==高亮显示==
  16.         footnotes: true, //脚注
  17.         autoSpace: true, //自动空格,适合中英文混合排版
  18.       },
  19.       math: {
  20.         engine: "KaTeX", //支持latex公式
  21.         inlineDigit: true, //内联公式可以接数字
  22.       },
  23.       hljs: {
  24.         style: "github", //代码段样式
  25.         lineNumber: true, //是否显示行号
  26.       },
  27.       anchor: 2, // 为标题添加锚点 0:不渲染;1:渲染于标题前;2:渲染于标题后
  28.       lang: "zh_CN", //中文
  29.       theme: {
  30.         current: "light", //light,dark,light,wechat
  31.       },
  32.       transform: (html) => {
  33.         // 使用正则表达式替换图片路径,并添加居中样式及题注
  34.         return html.replace(
  35.           /<img\s+[^>]*src="\.\/([^"]+)\.([a-zA-Z0-9]+)"\s*alt="([^"]*)"[^>]*>/g,
  36.           (match, p1, p2, altText) => {
  37.             // const newSrc = `${backendUrl}/blogs/resources/images/${postId}/${p1}.${p2}`;
  38.             const newSrc = `${p1}.${p2}`;
  39.             const imgWithCaption = `
  40.                     
  41.                         <img src="https://www.cnblogs.com/${newSrc}"  alt="${altText}">
  42.                         <p >${altText}</p>
  43.                     
  44.                     `;
  45.             return imgWithCaption;
  46.           }
  47.         );
  48.       },
  49.     });
  50.   } catch (error) {
  51.     console.error("初始化Markdown失败:", error);
  52.   }
  53. }
  54. document.addEventListener("DOMContentLoaded", initMarkdown);
复制代码
实现的过程很简单,就是在以文本的形式fetch远端的Markdown文档数据,然后使用Vditor.preview接口将获取的文本数据初始化到HTML的md-content元素中。关键是这个接口的初始化配置参数,具体的代表的功能笔者已经注释到代码中。其他的配置参数非常简单,按需进行配置即可;有点特别的是这个transform参数:
  1. transform: (html) => {
  2.     // 使用正则表达式替换图片路径,并添加居中样式及题注
  3.     return html.replace(
  4.         /<img\s+[^>]*src="\.\/([^"]+)\.([a-zA-Z0-9]+)"\s*alt="([^"]*)"[^>]*>/g,
  5.         (match, p1, p2, altText) => {
  6.         // const newSrc = `${backendUrl}/blogs/resources/images/${postId}/${p1}.${p2}`;
  7.         const newSrc = `${p1}.${p2}`;
  8.         const imgWithCaption = `
  9.                
  10.                     <img src="https://www.cnblogs.com/${newSrc}"  alt="${altText}">
  11.                     <p >${altText}</p>
  12.                
  13.                 `;
  14.         return imgWithCaption;
  15.         }
  16.     );
  17. },
复制代码
2.2 图片居中+题注

这个配置参数是用来配置渲染成HTML页面前的回调函数,我们可以用这个回调函数做什么呢?很简单,可以用来实现一些特殊的元素设计。比如说,Markdown格式标准非常简陋,只规定了如何引入图片,但是没有规定如何设置图片的样式。HTML的文档流是从上到下、从左到右的线性布局的,默认情况下图片是放在新的一行的最左边的。但是实际上更最美观的实现是图片居中展示,并且显示题注。
例如,在这里笔者的Markdown文档中图片相关的内容及最终实现效果是:
3.jpeg

在transform指定的回调函数中,也就是这里的html其实是个HTML字符串:
  1. <h3 id="图片">图片<svg viewBox="0 0 16 16" version="1.1" width="16" height="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></h3>
  2. <pre>![alt 文本](http://image-path.png)
  3. ![alt 文本](http://image-path.png "图片 Title 值")
  4. </pre>
  5. <p><img src="https://www.cnblogs.com/./head.jpg" alt="案例图片" /></p>
复制代码
要实现图片居中,并且增加图片题注就很简单了,通过正则表达式搜索到图片的元素
5.jpg
,将其替换成带题注并且居中的div元素,也就是:
  1. const imgWithCaption = `
  2.         
  3.             <img src="https://www.cnblogs.com/${newSrc}"  alt="${altText}">
  4.             <p >${altText}</p>
  5.         
  6.         `;
复制代码
最终,这个Markdown文档的图片的网页渲染效果就是:
7.jpeg

2.3 图片源更换

笔者实现的另外一个定制功能就是实现更换图片源地址。如果我们经常编写Markdown文档就知道,因为Markdown格式是文字与图片分离的,因此对图片资源的管理是件很麻烦的事情:如果使用base64编码嵌到Markdown文档里,就会影响可读性;如果使用在线图床,要么花钱要么花精力,要么既花钱又花精力。所以笔者还是推荐使用本地相对地址,例如:
  1. ![自定义Markdown文档图片元素的默认样式](./2.jpg)
复制代码
这样的写法,先保证本地文档能正常工作。但是Markdown文档在渲染成网页后这个相对地址就不一样生效了,往往需要对图片地址进行更换。更关键的是,像图片这种稍微重一点的资源最好放到CDN上,所以图片源地址的更换就是个强需求,也就是这部分代码的意思:
  1. return html.replace(
  2.     /<img\s+[^>]*src="\.\/([^"]+)\.([a-zA-Z0-9]+)"\s*alt="([^"]*)"[^>]*>/g,
  3.     (match, p1, p2, altText) => {
  4.     // const newSrc = `${backendUrl}/blogs/resources/images/${postId}/${p1}.${p2}`;
  5.     const newSrc = `${p1}.${p2}`;
  6.     //...
  7.     }
  8. );
复制代码
先用正则表达式找到图片元素的内容,然后对图片地址进行更换,更换成域内的短地址,也可以使用域外的长地址。也就是不要在Markdown文档本身下功夫,保证本地可以正常显示即可,更多的具体的定制功能通过Vditor渲染前回调来实现。
3. 结语

这个案例最终的显示效果如下所示:
8.jpeg

甚至可以表现脑图、流程图、时序图、甘特图、图表、五线谱、流程图等:
9.jpeg

不得不说Vditor不一定是所有Markdown编辑器中最好用,但一定是功能比较全的编辑器了,至少比笔者使用过的tui.editor要强不少。其实通过这个功能,你就可以大致实现一个技术博客网站了。具体思路是:把这个渲染过程工具化,将Markdown格式的博客文档批量生成静态网页,然后通过Web服务器进行发布;其实这也是一些静态博客网站工具的实现思路。
实现代码

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
4.jpg
您需要登录后才可以回帖 登录 | 立即注册