node.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > node.js > Node.js在线编辑Markdown

基于Node.js实现Markdown文档在线编辑功能

作者:belldeep

这篇文章主要介绍了如何基于 Node.js 和 mermaid.js 的 Web 服务器程序,实现在线编辑 Markdown 文档并支持 mermaid.js 流程图渲染的功能,感兴趣的小伙伴可以了解下

开发一个基于 Node.js 和 mermaid.js 的 Web 服务器程序,实现在线编辑 Markdown 文档并支持 mermaid.js 流程图渲染的功能。我会为你搭建一个完整、可直接运行的服务端程序,包含核心的 Web 服务、Markdown 解析和 Mermaid 渲染能力。

实现思路

完整实现代码

1. 项目初始化与依赖安装

首先创建项目并安装所需依赖:

创建项目目录

mkdir md-edit-app
cd md-edit-app

初始化 npm 项目

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. 服务器主程序 (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 应用
const app = express();

// 移除 mermaid 初始化代码 ↓
// mermaid.initialize({
//   startOnLoad: false,
//   theme: 'default',
//   securityLevel: 'loose' // 允许更多的渲染选项
// });

// 配置 Marked 解析器,添加 Mermaid 支持
const renderer = new marked.Renderer();

// 重写代码块渲染逻辑,识别 mermaid 代码块
renderer.code = (code, language) => {
  if (language === 'mermaid') {
    // 为 Mermaid 代码块生成容器(仅保留代码,渲染交给前端)
    return `<div class="mermaid">$[code]</div>`;
  }
  // 其他代码块使用默认渲染
  return `<pre><code class="language-${language}">$[code]</code></pre>`;
};

// 配置 marked
marked.setOptions({
  renderer: renderer,
  highlight: true,
  breaks: true,
  gfm: true // 启用 GitHub 风格的 Markdown
});

// 中间件配置
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));

// 设置模板引擎
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// 确保保存文件的目录存在
const DOCS_DIR = path.join(__dirname, 'docs');
fs.ensureDirSync(DOCS_DIR);

// 路由配置
// 首页 - 编辑器界面
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 内容不能为空' });
    }
    // 解析 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: '文件名和内容不能为空' });
    }
    // 拼接文件路径
    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: '文件不存在' });
    }
    // 读取文件内容
    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 });
  }
});

// 启动服务器
const PORT = 8000;
app.listen(PORT, () => {
  console.log(`服务器运行在: http://localhost:${PORT}`);
  console.log(`文档保存目录: ${DOCS_DIR}`);
});

3. 前端编辑器页面 (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="输入文件名(无需.md)" value="demo">
    <button id="saveBtn">保存文档</button>
    <button id="loadBtn">加载文档</button>
    <button id="refreshBtn">刷新预览</button>
  </div>
  
  <div class="container">
    <div class="editor-container">
      <textarea id="editor" placeholder="请输入 Markdown 内容...">
## Markdown 编辑器 (支持 Mermaid)

### 功能说明
- 支持标准 Markdown 语法
- 支持 Mermaid 流程图渲染
- 支持文档保存/加载

### Mermaid 示例
```mermaid
graph TD
    A[开始] --> B{选择操作}
    B -->|编辑| C[Markdown 编辑]
    B -->|预览| D[实时预览]
    C --> E[保存文档]
    D --> E
    E --> F[结束]

普通代码示例

  console.log('Hello, Markdown!');
  </textarea>
</div>
<div class="preview-container">
  <div id="preview" class="preview"></div>
</div>

运行与使用说明

创建目录结构

 md-edit-app/
   ├── app.js          // 服务器主程序
   ├── views/          // 模板目录
   │   └── editor.ejs  // 编辑器页面
   ├── public/         // 静态资源目录 (空即可)
   └── docs/      // 文档保存目录 (自动创建)

启动服务器

 node app.js

访问编辑器:打开浏览器访问 http://localhost:8000 即可看到 Markdown 编辑器界面

功能使用

总结

这个程序开箱即用,你可以直接复制代码运行,体验完整的 Markdown 在线编辑和 Mermaid 渲染功能。

到此这篇关于基于Node.js实现Markdown文档在线编辑功能的文章就介绍到这了,更多相关Node.js在线编辑Markdown内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文