使用Vditor將Markdown文檔渲染成網(wǎng)頁(yè)的具體案例(Vite+JS+Vditor)
1. 引言
編寫Markdown文檔現(xiàn)在可以說是程序員的必備技能了,因?yàn)镸arkdown很好地實(shí)現(xiàn)了內(nèi)容與排版分離,可以讓程序員更專注于內(nèi)容的創(chuàng)作?,F(xiàn)在很多技術(shù)文檔,博客發(fā)布甚至AI文字輸出的內(nèi)容都是以Markdown格式的形式輸出的。那么,Markdown文檔如何渲染成標(biāo)準(zhǔn)的Web網(wǎng)頁(yè)呢?這就要借助于一些支持Markdown格式的編輯器組件了。開源的Markdown編輯器組件有不少,Vditor是筆者認(rèn)為功能比較全的一款,在這里本文就通過Vditor來實(shí)現(xiàn)將一個(gè)Markdown文檔渲染成網(wǎng)頁(yè)的具體案例。
閱讀本文可能需要的前置文章:《使用Vite創(chuàng)建一個(gè)動(dòng)態(tài)網(wǎng)頁(yè)的前端項(xiàng)目》。
2. 實(shí)現(xiàn)
使用VS Code打開Vite初始化的工程,并且準(zhǔn)備一個(gè)Markdown文檔(筆者這里用的是Vditor的說明文檔),文件組織如下所示:
my-native-js-app
├── public
│ └── demo.md
├── src
│ ├── main.js
│ └── style.css
├── index.html
└── package.json
打開終端,輸入如下指令,安裝Vditor依賴包:
npm install vditor --save
2.1 基本配置
修改index.html中的內(nèi)容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" rel="external nofollow" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite App</title> </head> <body> <div id="app"> <div id="md-content"></div> </div> <script type="module" src="/src/main.js"></script> </body> </html>
其中,名稱為md-content的元素就是用來顯示Markdown文檔的容器。接著是style.css:
#app { width: 800px; margin: 0 auto; }
也非常簡(jiǎn)單,就是限制了顯示Markdown文檔的寬度以及設(shè)置居中顯示。對(duì)于一個(gè)文字為主的網(wǎng)頁(yè)來說,文檔的寬度不宜太寬,現(xiàn)代主流的文檔網(wǎng)頁(yè)的設(shè)計(jì)都是600~800px左右。
最后就是關(guān)鍵的實(shí)現(xiàn)主要功能代碼main.js:
import "./style.css"; import "vditor/dist/index.css"; import Vditor from "vditor"; async function initMarkdown() { try { const response = await fetch("/demo.md"); if (!response.ok) { throw new Error("網(wǎng)絡(luò)無響應(yīng)"); } const demoMd = await response.text(); // 顯示內(nèi)容 Vditor.preview(document.getElementById("md-content"), demoMd, { markdown: { toc: false, mark: true, //==高亮顯示== footnotes: true, //腳注 autoSpace: true, //自動(dòng)空格,適合中英文混合排版 }, math: { engine: "KaTeX", //支持latex公式 inlineDigit: true, //內(nèi)聯(lián)公式可以接數(shù)字 }, hljs: { style: "github", //代碼段樣式 lineNumber: true, //是否顯示行號(hào) }, anchor: 2, // 為標(biāo)題添加錨點(diǎn) 0:不渲染;1:渲染于標(biāo)題前;2:渲染于標(biāo)題后 lang: "zh_CN", //中文 theme: { current: "light", //light,dark,light,wechat }, transform: (html) => { // 使用正則表達(dá)式替換圖片路徑,并添加居中樣式及題注 return html.replace( /<img\s+[^>]*src="\.\/([^"]+)\.([a-zA-Z0-9]+)"\s*alt="([^"]*)"[^>]*>/g, (match, p1, p2, altText) => { // const newSrc = `${backendUrl}/blogs/resources/images/${postId}/${p1}.${p2}`; const newSrc = `${p1}.${p2}`; const imgWithCaption = ` <div style="text-align: center;"> <img src="${newSrc}" class="center-image" alt="${altText}"> <p class="caption">${altText}</p> </div> `; return imgWithCaption; } ); }, }); } catch (error) { console.error("初始化Markdown失敗:", error); } } document.addEventListener("DOMContentLoaded", initMarkdown);
實(shí)現(xiàn)的過程很簡(jiǎn)單,就是在以文本的形式fetch
遠(yuǎn)端的Markdown文檔數(shù)據(jù),然后使用Vditor.preview
接口將獲取的文本數(shù)據(jù)初始化到HTML的md-content
元素中。關(guān)鍵是這個(gè)接口的初始化配置參數(shù),具體的代表的功能筆者已經(jīng)注釋到代碼中。其他的配置參數(shù)非常簡(jiǎn)單,按需進(jìn)行配置即可;有點(diǎn)特別的是這個(gè)transform
參數(shù):
transform: (html) => { // 使用正則表達(dá)式替換圖片路徑,并添加居中樣式及題注 return html.replace( /<img\s+[^>]*src="\.\/([^"]+)\.([a-zA-Z0-9]+)"\s*alt="([^"]*)"[^>]*>/g, (match, p1, p2, altText) => { // const newSrc = `${backendUrl}/blogs/resources/images/${postId}/${p1}.${p2}`; const newSrc = `${p1}.${p2}`; const imgWithCaption = ` <div style="text-align: center;"> <img src="${newSrc}" class="center-image" alt="${altText}"> <p class="caption">${altText}</p> </div> `; return imgWithCaption; } ); },
2.2 圖片居中+題注
這個(gè)配置參數(shù)是用來配置渲染成HTML頁(yè)面前的回調(diào)函數(shù),我們可以用這個(gè)回調(diào)函數(shù)做什么呢?很簡(jiǎn)單,可以用來實(shí)現(xiàn)一些特殊的元素設(shè)計(jì)。比如說,Markdown格式標(biāo)準(zhǔn)非常簡(jiǎn)陋,只規(guī)定了如何引入圖片,但是沒有規(guī)定如何設(shè)置圖片的樣式。HTML的文檔流是從上到下、從左到右的線性布局的,默認(rèn)情況下圖片是放在新的一行的最左邊的。但是實(shí)際上更最美觀的實(shí)現(xiàn)是圖片居中展示,并且顯示題注。
例如,在這里筆者的Markdown文檔中圖片相關(guān)的內(nèi)容及最終實(shí)現(xiàn)效果是:
在transform指定的回調(diào)函數(shù)中,也就是這里的html其實(shí)是個(gè)HTML字符串:
<h3 id="圖片">圖片<a id="vditorAnchor-圖片" class="vditor-anchor" href="#圖片" rel="external nofollow" ><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></a></h3> <pre><code>  </code></pre> <p><img src="./head.jpg" alt="案例圖片" /></p>
要實(shí)現(xiàn)圖片居中,并且增加圖片題注就很簡(jiǎn)單了,通過正則表達(dá)式搜索到圖片的元素<img src="./head.jpg" alt="案例圖片" />
,將其替換成帶題注并且居中的div
元素,也就是:
const imgWithCaption = ` <div style="text-align: center;"> <img src="${newSrc}" class="center-image" alt="${altText}"> <p class="caption">${altText}</p> </div> `;
最終,這個(gè)Markdown文檔的圖片的網(wǎng)頁(yè)渲染效果就是:
2.3 圖片源更換
筆者實(shí)現(xiàn)的另外一個(gè)定制功能就是實(shí)現(xiàn)更換圖片源地址。如果我們經(jīng)常編寫Markdown文檔就知道,因?yàn)镸arkdown格式是文字與圖片分離的,因此對(duì)圖片資源的管理是件很麻煩的事情:如果使用base64編碼嵌到Markdown文檔里,就會(huì)影響可讀性;如果使用在線圖床,要么花錢要么花精力,要么既花錢又花精力。所以筆者還是推薦使用本地相對(duì)地址,例如:

這樣的寫法,先保證本地文檔能正常工作。但是Markdown文檔在渲染成網(wǎng)頁(yè)后這個(gè)相對(duì)地址就不一樣生效了,往往需要對(duì)圖片地址進(jìn)行更換。更關(guān)鍵的是,像圖片這種稍微重一點(diǎn)的資源最好放到CDN上,所以圖片源地址的更換就是個(gè)強(qiáng)需求,也就是這部分代碼的意思:
return html.replace( /<img\s+[^>]*src="\.\/([^"]+)\.([a-zA-Z0-9]+)"\s*alt="([^"]*)"[^>]*>/g, (match, p1, p2, altText) => { // const newSrc = `${backendUrl}/blogs/resources/images/${postId}/${p1}.${p2}`; const newSrc = `${p1}.${p2}`; //... } );
先用正則表達(dá)式找到圖片元素的內(nèi)容,然后對(duì)圖片地址進(jìn)行更換,更換成域內(nèi)的短地址,也可以使用域外的長(zhǎng)地址。也就是不要在Markdown文檔本身下功夫,保證本地可以正常顯示即可,更多的具體的定制功能通過Vditor渲染前回調(diào)來實(shí)現(xiàn)。
3. 結(jié)語(yǔ)
這個(gè)案例最終的顯示效果如下所示:
甚至可以表現(xiàn)腦圖、流程圖、時(shí)序圖、甘特圖、圖表、五線譜、流程圖等:
不得不說Vditor不一定是所有Markdown編輯器中最好用,但一定是功能比較全的編輯器了,至少比筆者使用過的tui.editor要強(qiáng)不少。其實(shí)通過這個(gè)功能,你就可以大致實(shí)現(xiàn)一個(gè)技術(shù)博客網(wǎng)站了。具體思路是:把這個(gè)渲染過程工具化,將Markdown格式的博客文檔批量生成靜態(tài)網(wǎng)頁(yè),然后通過Web服務(wù)器進(jìn)行發(fā)布;其實(shí)這也是一些靜態(tài)博客網(wǎng)站工具的實(shí)現(xiàn)思路。
到此這篇關(guān)于使用Vditor將Markdown文檔渲染成網(wǎng)頁(yè)(Vite+JS+Vditor)的文章就介紹到這了,更多相關(guān)Markdown文檔渲染網(wǎng)頁(yè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript檢測(cè)對(duì)象中是否存在某個(gè)屬性判斷方法小結(jié)
檢測(cè)對(duì)象中屬性的存在與否可以通過以下幾種方法來判斷:使用in關(guān)鍵字、使用對(duì)象的hasOwnProperty()方法、用undefined判斷、在條件語(yǔ)句中直接判斷,感興趣的朋友可以了解下哈2013-05-05使用Visual?Studio?2022開發(fā)前端的詳細(xì)教程
這篇文章主要介紹了使用Visual?Studio?2022開發(fā)前端,在瀏覽器中可以使用CDN源引用需要的客戶端庫(kù),可如果在企業(yè)內(nèi)網(wǎng)使用,無法訪問CDN源時(shí),需要將客戶端庫(kù)下載到本地使用,需要的朋友可以參考下2022-05-05jsvascript圖像處理—(計(jì)算機(jī)視覺應(yīng)用)圖像金字塔
上一篇文章,我們講解了邊緣梯度計(jì)算函數(shù),這篇文章我們來了解圖像金字塔;圖像金字塔被廣泛用于計(jì)算機(jī)視覺應(yīng)用中;圖像金字塔是一個(gè)圖像集合,集合中所有的圖像都源于同一個(gè)原始圖像,而且是通過對(duì)原始圖像連續(xù)降采樣獲得的2013-01-01js簡(jiǎn)單實(shí)現(xiàn)用戶注冊(cè)信息的校驗(yàn)代碼
這篇文章介紹了js簡(jiǎn)單實(shí)現(xiàn)用戶注冊(cè)信息的校驗(yàn)代碼,有需要的朋友可以參考一下2013-11-11js鎖屏解屏通過對(duì)$.ajax進(jìn)行封裝實(shí)現(xiàn)
js鎖屏解屏是通過對(duì)$.ajax進(jìn)行封裝實(shí)現(xiàn)的,需要的朋友可以參考下2014-07-07怎樣用JavaScript實(shí)現(xiàn)原型模式
這篇文章主要介紹了怎樣用JavaScript實(shí)現(xiàn)原型模式,想學(xué)習(xí)設(shè)計(jì)模式的同學(xué),可以參考下2021-04-04如何基于uni-app實(shí)現(xiàn)微信小程序一鍵登錄與退出登錄功能
uni-app 是使用vue的語(yǔ)法+小程序的標(biāo)簽和API的一套框架,是一套代碼多端使用,目前是大前端的一種趨勢(shì),下面這篇文章主要給大家介紹了關(guān)于如何基于uni-app實(shí)現(xiàn)微信小程序一鍵登錄與退出登錄功能的相關(guān)資料,需要的朋友可以參考下2022-09-09