使用Vditor將Markdown文檔渲染成網頁(Vite+JS+Vditor)

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依賴包:

npm install vditor --save

2.1 基本配置

修改index.html中的內容:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><link rel="icon" type="image/svg+xml" href="/vite.svg" /><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; 
}

也非常簡單,就是限制了顯示Markdown文檔的寬度以及設置居中顯示。對于一個文字為主的網頁來說,文檔的寬度不宜太寬,現代主流的文檔網頁的設計都是600~800px左右。

最后就是關鍵的實現主要功能代碼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("網絡無響應");}const demoMd = await response.text();// 顯示內容Vditor.preview(document.getElementById("md-content"), demoMd, {markdown: {toc: false,mark: true, //==高亮顯示==footnotes: true, //腳注autoSpace: true, //自動空格,適合中英文混合排版},math: {engine: "KaTeX", //支持latex公式inlineDigit: true, //內聯公式可以接數字},hljs: {style: "github", //代碼段樣式lineNumber: true, //是否顯示行號},anchor: 2, // 為標題添加錨點 0:不渲染;1:渲染于標題前;2:渲染于標題后lang: "zh_CN", //中文theme: {current: "light", //light,dark,light,wechat},transform: (html) => {// 使用正則表達式替換圖片路徑,并添加居中樣式及題注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);

實現的過程很簡單,就是在以文本的形式fetch遠端的Markdown文檔數據,然后使用Vditor.preview接口將獲取的文本數據初始化到HTML的md-content元素中。關鍵是這個接口的初始化配置參數,具體的代表的功能筆者已經注釋到代碼中。其他的配置參數非常簡單,按需進行配置即可;有點特別的是這個transform參數:

transform: (html) => {// 使用正則表達式替換圖片路徑,并添加居中樣式及題注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 圖片居中+題注

這個配置參數是用來配置渲染成HTML頁面前的回調函數,我們可以用這個回調函數做什么呢?很簡單,可以用來實現一些特殊的元素設計。比如說,Markdown格式標準非常簡陋,只規定了如何引入圖片,但是沒有規定如何設置圖片的樣式。HTML的文檔流是從上到下、從左到右的線性布局的,默認情況下圖片是放在新的一行的最左邊的。但是實際上更最美觀的實現是圖片居中展示,并且顯示題注。

例如,在這里筆者的Markdown文檔中圖片相關的內容及最終實現效果是:

使用VS Code展示Markdown文檔圖片相關的內容

在transform指定的回調函數中,也就是這里的html其實是個HTML字符串:

<h3 id="圖片">圖片<a id="vditorAnchor-圖片" class="vditor-anchor" href="#圖片"><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>![alt 文本](http://image-path.png)
![alt 文本](http://image-path.png &quot;圖片 Title 值&quot;)
</code></pre>
<p><img src="./head.jpg" alt="案例圖片" /></p>

要實現圖片居中,并且增加圖片題注就很簡單了,通過正則表達式搜索到圖片的元素<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>`;

最終,這個Markdown文檔的圖片的網頁渲染效果就是:

自定義Markdown文檔圖片元素的默認樣式

2.3 圖片源更換

筆者實現的另外一個定制功能就是實現更換圖片源地址。如果我們經常編寫Markdown文檔就知道,因為Markdown格式是文字與圖片分離的,因此對圖片資源的管理是件很麻煩的事情:如果使用base64編碼嵌到Markdown文檔里,就會影響可讀性;如果使用在線圖床,要么花錢要么花精力,要么既花錢又花精力。所以筆者還是推薦使用本地相對地址,例如:

![自定義Markdown文檔圖片元素的默認樣式](./2.jpg)

這樣的寫法,先保證本地文檔能正常工作。但是Markdown文檔在渲染成網頁后這個相對地址就不一樣生效了,往往需要對圖片地址進行更換。更關鍵的是,像圖片這種稍微重一點的資源最好放到CDN上,所以圖片源地址的更換就是個強需求,也就是這部分代碼的意思:

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}`;//...}
);

先用正則表達式找到圖片元素的內容,然后對圖片地址進行更換,更換成域內的短地址,也可以使用域外的長地址。也就是不要在Markdown文檔本身下功夫,保證本地可以正常顯示即可,更多的具體的定制功能通過Vditor渲染前回調來實現。

3. 結語

這個案例最終的顯示效果如下所示:
Vditor將Markdown渲染成網頁的效果
甚至可以表現腦圖、流程圖、時序圖、甘特圖、圖表、五線譜、流程圖等:

Vditor將Markdown渲染成網頁的效果

不得不說Vditor不一定是所有Markdown編輯器中最好用,但一定是功能比較全的編輯器了,至少比筆者使用過的tui.editor要強不少。其實通過這個功能,你就可以大致實現一個技術博客網站了。具體思路是:把這個渲染過程工具化,將Markdown格式的博客文檔批量生成靜態網頁,然后通過Web服務器進行發布;其實這也是一些靜態博客網站工具的實現思路。

實現代碼

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/82923.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/82923.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/82923.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Day 40

單通道圖片的規范寫法 import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader , Dataset from torchvision import datasets, transforms import matplotlib.pyplot as plt import warnings warnings.filterwarnings(&q…

SPSS跨域分類:自監督知識+軟模板優化

1. 圖1:SPSS方法流程圖 作用:展示了SPSS方法的整體流程,從數據預處理到模型預測的關鍵步驟。核心內容: 領域知識提取:使用三種詞性標注工具(NLTK、spaCy、TextBlob)從源域和目標域提取名詞或形容詞(如例句中提取“excellent”“good”等形容詞)。詞匯交集與聚類:對提…

2025年通用 Linux 服務器操作系統該如何選擇?

2025年通用 Linux 服務器操作系統該如何選擇&#xff1f; 服務器操作系統的選擇對一個企業IT和云服務影響很大&#xff0c;主推的操作系統在后期更換的成本很高&#xff0c;而且也有很大的遷移風險&#xff0c;所以企業在選擇服務器操作系統時要尤為重視。 之前最流行的服務器…

如何在 Django 中集成 MCP Server

目錄 背景說明第一步&#xff1a;使用 ASGI第二步&#xff1a;修改 asgi.py 中的應用第三步&#xff1a;Django 數據的異步查詢 背景說明 有幾個原因導致 Django 集成 MCP Server 比較麻煩 目前支持的 MCP 服務是 SSE 協議的&#xff0c;需要長連接&#xff0c;但一般來講 Dj…

天拓四方工業互聯網平臺賦能:地鐵電力配電室綜合監控與無人巡檢,實現效益與影響的雙重顯著提升

隨著城市化進程的不斷加快&#xff0c;城市軌道交通作為緩解交通壓力、提升出行效率的重要方式&#xff0c;在全國各大城市中得到了迅猛發展。地鐵電力配電室作為核心供電設施&#xff0c;其基礎設施的安全性、穩定性和智能化水平也面臨更高要求。 本文將圍繞“工業物聯網平臺…

算法打卡第11天

36.有效的括號 &#xff08;力扣20題&#xff09; 示例 1&#xff1a; **輸入&#xff1a;**s “()” **輸出&#xff1a;**true 示例 2&#xff1a; **輸入&#xff1a;**s “()[]{}” **輸出&#xff1a;**true 示例 3&#xff1a; **輸入&#xff1a;**s “(]”…

python 包管理工具uv

uv --version uv python find uv python list export UV_DEFAULT_INDEX"https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" # 換成私有的repo export UV_HTTP_TIMEOUT120 uv python install 3.12 uv venv myenv --python 3.12 --seed uvhttps://docs.ast…

spring的多語言怎么實現?

1.創建springboot項目&#xff0c;并配置application.properties文件 spring.messages.basenamemessages spring.messages.encodingUTF-8 spring.messages.fallback-to-system-localefalsespring.thymeleaf.cachefalse spring.thymeleaf.prefixclasspath:/templates/ spring.t…

JAVA:Kafka 消息可靠性詳解與實踐樣例

?? 1、簡述 Apache Kafka 是高吞吐、可擴展的流處理平臺,在分布式架構中廣泛應用于日志采集、事件驅動和微服務解耦場景。但在使用過程中,消息是否會丟?何時丟?如何防止丟? 是很多開發者關心的問題。 Kafka 提供了一套完整的機制來保障消息從生產者 ? Broker ? 消費…

【AI非常道】二零二五年五月,AI非常道

經常在社區看到一些非常有啟發或者有收獲的話語&#xff0c;但是&#xff0c;往往看過就成為過眼云煙&#xff0c;有時再想去找又找不到。索性&#xff0c;今年開始&#xff0c;看到好的言語&#xff0c;就記錄下來&#xff0c;一月一發布&#xff0c;亦供大家參考。 前面的記…

C++哈希

一.哈希概念 哈希又叫做散列。本質就是通過哈希函數把關鍵字key和存儲位置建立映射關系&#xff0c;查找時通過這個哈希函數計算出key存儲的位置&#xff0c;進行快速查找。 上述概念可能不那么好懂&#xff0c;下面的例子可以輔助我們理解。 無論是數組還是鏈表&#xff0c;查…

iOS 使用CocoaPods 添加Alamofire 提示錯誤的問題

Sandbox: rsync(59817) deny(1) file-write-create /Users/aaa/Library/Developer/Xcode/DerivedData/myApp-bpwnzikesjzmbadkbokxllvexrrl/Build/Products/Debug-iphoneos/myApp.app/Frameworks/Alamofire.framework/Alamofire.bundle把這個改成 no 2 設置配置文件

mysql的Memory引擎的深入了解

目錄 1、Memory引擎介紹 2、Memory內存結構 3、內存表的鎖 4、持久化 5、優缺點 6、應用 前言 Memory 存儲引擎 是 MySQL 中一種高性能但非持久化的存儲方案&#xff0c;適合臨時數據存儲和緩存場景。其核心優勢在于極快的讀寫速度&#xff0c;需注意數據丟失風險和內存占…

若依項目AI 助手代碼解析

基于 Vue.js 和 Element UI 的 AI 助手組件 一、組件整體結構 這個 AI 助手組件由三部分組成&#xff1a; 懸浮按鈕&#xff1a;點擊后展開 / 收起對話窗口對話窗口&#xff1a;顯示歷史消息和輸入框API 調用邏輯&#xff1a;與 AI 服務通信并處理響應 <template><…

Vue2的diff算法

diff算法的目的是為了找出需要更新的節點&#xff0c;而未變化的節點則可以復用 新舊列表的頭尾先互相比較。未找到可復用則開始遍歷&#xff0c;對比過程中指針逐漸向列表中間靠攏&#xff0c;直到遍歷完其中一個列表 具體策略如下&#xff1a; 同層級比較 Vue2的diff算法只…

mongodb集群之分片集群

目錄 1. 適用場景2. 集群搭建如何搭建搭建實例Linux搭建實例(待定)Windows搭建實例1.資源規劃2. 配置conf文件3. 按順序啟動不同角色的mongodb實例4. 初始化config、shard集群信息5. 通過router進行分片配置 1. 適用場景 數據量大影響性能 數據量大概達到千萬級或億級的時候&…

DEEPSEEK幫寫的STM32消息流函數,直接可用.已經測試

#include "main.h" #include "MessageBuffer.h"static RingBuffer msgQueue {0};// 初始化隊列 void InitQueue(void) {msgQueue.head 0;msgQueue.tail 0;msgQueue.count 0; }// 檢查隊列狀態 type_usart_queue_status GetQueueStatus(void) {if (msgQ…

華為歐拉系統中部署FTP服務與Filestash應用:實現高效文件管理和共享

華為歐拉系統中部署FTP服務與Filestash應用:實現高效文件管理和共享 前言一、相關服務介紹1.1 Huawei Cloud EulerOS介紹1.2 Filestash介紹1.3 華為云Flexus應用服務器L實例介紹二、本次實踐介紹2.1 本次實踐介紹2.2 本次環境規劃三、檢查云服務器環境3.1 登錄華為云3.2 SSH遠…

React---day5

4、React的組件化 組件的分類&#xff1a; 根據組件的定義方式&#xff0c;可以分為&#xff1a;函數組件(Functional Component )和類組件(Class Component)&#xff1b;根據組件內部是否有狀態需要維護&#xff0c;可以分成&#xff1a;無狀態組件(Stateless Component )和…

測試策略:AI模型接口的單元測試與穩定性測試

測試策略:AI模型接口的單元測試與穩定性測試 在構建支持AI能力的系統中,開發者不僅要關注業務邏輯的正確性,也必須保障AI模型接口在各種環境下都能穩定運行。這就要求我們在開發階段制定清晰的測試策略,從功能驗證到性能保障,逐步推進系統可用性、可維護性與可擴展性的提…