基于Node.js實(shí)現(xiàn)Markdown文檔在線編輯功能
開(kāi)發(fā)一個(gè)基于 Node.js 和 mermaid.js 的 Web 服務(wù)器程序,實(shí)現(xiàn)在線編輯 Markdown 文檔并支持 mermaid.js 流程圖渲染的功能。我會(huì)為你搭建一個(gè)完整、可直接運(yùn)行的服務(wù)端程序,包含核心的 Web 服務(wù)、Markdown 解析和 Mermaid 渲染能力。
實(shí)現(xiàn)思路
- 使用
Express作為基礎(chǔ) Web 框架搭建服務(wù)器 - 使用
marked解析 Markdown 內(nèi)容,并配置 Mermaid 擴(kuò)展 - 使用
mermaid實(shí)現(xiàn)流程圖的渲染 - 提供一個(gè)簡(jiǎn)潔的前端編輯界面,支持實(shí)時(shí)預(yù)覽
- 實(shí)現(xiàn)基本的文件保存/加載功能(本地文件存儲(chǔ))
完整實(shí)現(xiàn)代碼
1. 項(xiàng)目初始化與依賴安裝
首先創(chuàng)建項(xiàng)目并安裝所需依賴:
創(chuàng)建項(xiàng)目目錄
mkdir md-edit-app cd md-edit-app
初始化 npm 項(xiàng)目
npm init -y
安裝核心依賴
npm install express@4 marked@12 npm install cors body-parser fs-extra ejs
我用的 node.js 版本: 18.20 , 搭配的版本是
npm install express@4.18.3 marked@12.0.2 npm install cors@2.8.5 body-parser@1.20.2 fs-extra@11.2.0 ejs@3.1.9
2. 服務(wù)器主程序 (app.js)
const express = require('express');
const marked = require('marked');
// 移除 const mermaid = require('mermaid');
const cors = require('cors');
const bodyParser = require('body-parser');
const fs = require('fs-extra');
const path = require('path');
// 初始化 Express 應(yīng)用
const app = express();
// 移除 mermaid 初始化代碼 ↓
// mermaid.initialize({
// startOnLoad: false,
// theme: 'default',
// securityLevel: 'loose' // 允許更多的渲染選項(xiàng)
// });
// 配置 Marked 解析器,添加 Mermaid 支持
const renderer = new marked.Renderer();
// 重寫代碼塊渲染邏輯,識(shí)別 mermaid 代碼塊
renderer.code = (code, language) => {
if (language === 'mermaid') {
// 為 Mermaid 代碼塊生成容器(僅保留代碼,渲染交給前端)
return `<div class="mermaid">$[code]</div>`;
}
// 其他代碼塊使用默認(rèn)渲染
return `<pre><code class="language-${language}">$[code]</code></pre>`;
};
// 配置 marked
marked.setOptions({
renderer: renderer,
highlight: true,
breaks: true,
gfm: true // 啟用 GitHub 風(fēng)格的 Markdown
});
// 中間件配置
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
// 設(shè)置模板引擎
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// 確保保存文件的目錄存在
const DOCS_DIR = path.join(__dirname, 'docs');
fs.ensureDirSync(DOCS_DIR);
// 路由配置
// 首頁(yè) - 編輯器界面
app.get('/', (req, res) => {
res.render('editor', { title: 'Markdown 在線編輯器 (支持Mermaid)' });
});
// 解析 Markdown 為 HTML (API)
app.post('/api/parse', (req, res) => {
try {
const { markdown } = req.body;
if (!markdown) {
return res.status(400).json({ error: 'Markdown 內(nèi)容不能為空' });
}
// 解析 Markdown 為 HTML
const html = marked.parse(markdown);
res.json({ html });
} catch (error) {
res.status(500).json({ error: '解析 Markdown 失敗: ' + error.message });
}
});
// 保存文檔 (API)
app.post('/api/save', (req, res) => {
try {
const { filename, content } = req.body;
if (!filename || !content) {
return res.status(400).json({ error: '文件名和內(nèi)容不能為空' });
}
// 拼接文件路徑
const filePath = path.join(DOCS_DIR, `${filename}.md`);
// 寫入文件
fs.writeFileSync(filePath, content, 'utf8');
res.json({ success: true, message: '文件保存成功', filePath });
} catch (error) {
res.status(500).json({ error: '保存文件失敗: ' + error.message });
}
});
// 加載文檔 (API)
app.get('/api/load/:filename', (req, res) => {
try {
const { filename } = req.params;
const filePath = path.join(DOCS_DIR, `${filename}.md`);
// 檢查文件是否存在
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: '文件不存在' });
}
// 讀取文件內(nèi)容
const content = fs.readFileSync(filePath, 'utf8');
res.json({ success: true, content });
} catch (error) {
res.status(500).json({ error: '加載文件失敗: ' + error.message });
}
});
// 獲取文檔列表 (API)
app.get('/api/docs', (req, res) => {
try {
// 讀取目錄下所有 .md 文件
const files = fs.readdirSync(DOCS_DIR)
.filter(file => path.extname(file) === '.md')
.map(file => ({
name: path.basename(file, '.md'),
path: file
}));
res.json({ success: true, docs: files });
} catch (error) {
res.status(500).json({ error: '獲取文檔列表失敗: ' + error.message });
}
});
// 啟動(dòng)服務(wù)器
const PORT = 8000;
app.listen(PORT, () => {
console.log(`服務(wù)器運(yùn)行在: http://localhost:${PORT}`);
console.log(`文檔保存目錄: ${DOCS_DIR}`);
});
3. 前端編輯器頁(yè)面 (views/editor.ejs)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
flex-direction: column;
height: 100vh;
}
.header {
background: #2c3e50;
color: white;
padding: 1rem;
text-align: center;
}
.container {
display: flex;
flex: 1;
overflow: hidden;
}
.editor-container, .preview-container {
flex: 1;
padding: 1rem;
overflow: hidden;
border: 1px solid #ddd;
}
textarea {
width: 100%;
height: 100%;
padding: 1rem;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 14px;
border: none;
outline: none;
resize: none;
}
.preview {
width: 100%;
height: 100%;
overflow-y: auto;
padding: 1rem;
background: #f9f9f9;
}
.controls {
padding: 1rem;
background: #f1f1f1;
display: flex;
gap: 1rem;
}
button {
padding: 0.5rem 1rem;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #2980b9;
}
.file-input {
padding: 0.5rem;
}
pre {
background: #f4f4f4;
padding: 1rem;
border-radius: 4px;
overflow-x: auto;
}
code {
font-family: 'Consolas', 'Monaco', monospace;
}
</style>
</head>
<body>
<div class="header">
<h1>Markdown 在線編輯器 (支持 Mermaid 流程圖)</h1>
</div>
<div class="controls">
<input type="text" id="filename" placeholder="輸入文件名(無(wú)需.md)" value="demo">
<button id="saveBtn">保存文檔</button>
<button id="loadBtn">加載文檔</button>
<button id="refreshBtn">刷新預(yù)覽</button>
</div>
<div class="container">
<div class="editor-container">
<textarea id="editor" placeholder="請(qǐng)輸入 Markdown 內(nèi)容...">
## Markdown 編輯器 (支持 Mermaid)
### 功能說(shuō)明
- 支持標(biāo)準(zhǔn) Markdown 語(yǔ)法
- 支持 Mermaid 流程圖渲染
- 支持文檔保存/加載
### Mermaid 示例
```mermaid
graph TD
A[開(kāi)始] --> B{選擇操作}
B -->|編輯| C[Markdown 編輯]
B -->|預(yù)覽| D[實(shí)時(shí)預(yù)覽]
C --> E[保存文檔]
D --> E
E --> F[結(jié)束]
普通代碼示例
console.log('Hello, Markdown!');
</textarea> </div> <div class="preview-container"> <div id="preview" class="preview"></div> </div>
運(yùn)行與使用說(shuō)明
創(chuàng)建目錄結(jié)構(gòu):
md-edit-app/
├── app.js // 服務(wù)器主程序
├── views/ // 模板目錄
│ └── editor.ejs // 編輯器頁(yè)面
├── public/ // 靜態(tài)資源目錄 (空即可)
└── docs/ // 文檔保存目錄 (自動(dòng)創(chuàng)建)
啟動(dòng)服務(wù)器:
node app.js
訪問(wèn)編輯器:打開(kāi)瀏覽器訪問(wèn) http://localhost:8000 即可看到 Markdown 編輯器界面
功能使用:
- 在左側(cè)編輯框輸入 Markdown 內(nèi)容(包含 Mermaid 代碼塊)
- 點(diǎn)擊「刷新預(yù)覽」查看右側(cè)渲染效果
- 輸入文件名后,點(diǎn)擊「保存文檔」可將內(nèi)容保存到服務(wù)器
- 輸入已保存的文件名,點(diǎn)擊「加載文檔」可加載保存的內(nèi)容
總結(jié)
- 核心功能:該程序基于 Express 搭建 Web 服務(wù)器,使用 marked 解析 Markdown,集成 mermaid.js 實(shí)現(xiàn)流程圖渲染,提供了完整的在線編輯、預(yù)覽、保存、加載功能。
- 技術(shù)棧:Node.js + Express + marked (Markdown解析) + mermaid.js (流程圖渲染) + EJS (模板引擎)。
- 擴(kuò)展建議:可進(jìn)一步添加用戶認(rèn)證、多人協(xié)作、云存儲(chǔ)、更多 Markdown 擴(kuò)展(如表格、公式)等功能,也可優(yōu)化前端界面使其更美觀易用。
這個(gè)程序開(kāi)箱即用,你可以直接復(fù)制代碼運(yùn)行,體驗(yàn)完整的 Markdown 在線編輯和 Mermaid 渲染功能。
到此這篇關(guān)于基于Node.js實(shí)現(xiàn)Markdown文檔在線編輯功能的文章就介紹到這了,更多相關(guān)Node.js在線編輯Markdown內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用Node.js了解與測(cè)量HTTP所花費(fèi)的時(shí)間詳解
這篇文章主要給大家介紹了關(guān)于利用Node.js了解與測(cè)量HTTP所花費(fèi)的時(shí)間的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09
簡(jiǎn)單談?wù)刵ode.js 版本控制 nvm和 n
大量開(kāi)發(fā)者的貢獻(xiàn)使Node版本的迭代速度很快,版本很多(橫跨0.6到0.11),所以升級(jí)Node版本就成為了一個(gè)問(wèn)題。目前有n和nvm這兩個(gè)工具可以對(duì)Node進(jìn)行無(wú)痛升級(jí),本文簡(jiǎn)單介紹一下二者的使用。2015-10-10
NodeJS設(shè)計(jì)模式總結(jié)【單例模式,適配器模式,裝飾模式,觀察者模式】
這篇文章主要介紹了NodeJS設(shè)計(jì)模式,結(jié)合實(shí)例形式總結(jié)分析了nodejs單例模式,適配器模式,裝飾模式,觀察者模式的概念、原理與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-09-09
Node.js前后端交互實(shí)現(xiàn)用戶登陸的實(shí)踐
本文主要介紹了Node.js前后端交互實(shí)現(xiàn)用戶登陸的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
Node.js 使用axios讀寫influxDB的方法示例
這篇文章主要介紹了Node.js 使用axios讀寫influxDB的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10

