You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js+MongoDB环境中实现Quill编辑器?含博客实践疑问

Node.js + MongoDB 环境下用 Quill 搭建博客可视化编辑方案

嘿,你的这个方案完全可行!Quill 本身就围绕 Delta 格式设计,这种轻量结构化的内容存在 MongoDB(文档型数据库)里简直天作之合,再用 quill-render 转成 HTML 展示也完全没问题。我来一步步给你拆解实现步骤,帮你搞定个人博客的可视化编辑功能:

一、先确认方案可行性

Quill 的 Delta 是它的核心数据格式,本质是描述内容变化的 JSON 对象,相比直接存 HTML 更灵活、体积更小,而且方便后续修改和扩展。MongoDB 作为文档数据库,天然支持存储这种 JSON 结构的数据。quill-render 确实能把 Delta 准确转换成前端能展示的 HTML,所以你的思路完全没问题,放心推进就行!

二、具体实现步骤

1. 前端集成 Quill 编辑器

首先得把 Quill 加到你的前端页面里:

  • 可以通过 npm 安装:npm install quill,然后在代码里导入;或者直接用 CDN 引入 Quill 的 JS 和 CSS 文件
  • 给编辑器准备一个容器:<div id="editor"></div>
  • 初始化编辑器,配置工具栏(尤其是要开启图片上传功能):
import Quill from 'quill';
import 'quill/dist/quill.snow.css';

const quill = new Quill('#editor', {
  theme: 'snow',
  toolbar: [
    ['bold', 'italic', 'underline', 'strike'],
    ['blockquote', 'code-block'],
    [{ 'header': 1 }, { 'header': 2 }],
    [{ 'list': 'ordered'}, { 'list': 'bullet' }],
    [{ 'color': [] }, { 'background': [] }],
    ['link', 'image'], // 必须包含图片按钮
    ['clean']
  ]
});

2. 处理图片上传(关键!别用默认的 base64)

默认情况下,Quill 插入图片会转成 base64 存在 Delta 里,这种方式体积大,存数据库非常不划算。咱们得改成上传到服务器/云存储,只存图片 URL:

  • 监听 Quill 的图片上传事件,或者自定义工具栏的图片按钮行为:
// 自定义图片上传逻辑
const toolbar = quill.getModule('toolbar');
toolbar.addHandler('image', function () {
  const input = document.createElement('input');
  input.setAttribute('type', 'file');
  input.setAttribute('accept', 'image/*');
  input.click();

  input.onchange = async function () {
    const file = input.files[0];
    const formData = new FormData();
    formData.append('image', file);

    // 调用后端上传接口
    const res = await fetch('/api/upload-image', {
      method: 'POST',
      body: formData
    });
    const data = await res.json();

    // 把返回的图片URL插入编辑器
    const range = quill.getSelection();
    quill.insertEmbed(range.index, 'image', data.imageUrl);
    quill.setSelection(range.index + 1);
  };
});

3. 后端实现图片上传接口(Node.js + Express)

用 Express 写一个接口处理图片上传,这里以本地存储为例(也可以换成阿里云OSS、七牛云等):

  • 先安装依赖:npm install multer(处理文件上传的中间件)
  • 写上传接口:
const express = require('express');
const multer = require('multer');
const path = require('path');

const router = express.Router();

// 配置multer存储路径和文件名
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname, '../public/uploads')); // 确保uploads文件夹存在
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + '-' + file.originalname); // 避免文件名重复
  }
});

const upload = multer({ storage: storage });

router.post('/upload-image', upload.single('image'), (req, res) => {
  // 返回图片的访问URL,比如http://localhost:3000/uploads/xxx.jpg
  const imageUrl = `/uploads/${req.file.filename}`;
  res.json({ imageUrl });
});

module.exports = router;

别忘了在 Express 里配置静态文件服务,让前端能访问上传的图片:app.use(express.static('public'));

4. 存储 Delta 到 MongoDB

接下来把编辑器的 Delta 内容和博客其他字段(标题、分类等)存到 MongoDB:

  • 定义 MongoDB 的 Schema(用 Mongoose):
const mongoose = require('mongoose');

const blogSchema = new mongoose.Schema({
  title: { type: String, required: true },
  contentDelta: { type: Object, required: true }, // 直接存Delta对象
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Blog', blogSchema);
  • 写保存博客的后端接口:
const Blog = require('../models/Blog');

router.post('/save-blog', async (req, res) => {
  try {
    const { title, contentDelta } = req.body;
    const blog = new Blog({ title, contentDelta });
    await blog.save();
    res.json({ success: true, blogId: blog._id });
  } catch (err) {
    res.status(500).json({ success: false, message: err.message });
  }
});
  • 前端提交内容时,调用这个接口:
// 点击保存按钮时触发
async function saveBlog() {
  const title = document.getElementById('title').value;
  const contentDelta = quill.getContents(); // 获取编辑器的Delta内容
  const res = await fetch('/api/save-blog', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ title, contentDelta })
  });
  const data = await res.json();
  if (data.success) {
    alert('博客保存成功!');
  }
}

5. 从 MongoDB 取出 Delta 并渲染为 HTML

用 quill-render 把 Delta 转换成 HTML,用于博客展示:

  • 安装 quill-render:npm install quill-render
  • 写获取博客并渲染的接口:
const quillRender = require('quill-render');
const Blog = require('../models/Blog');

router.get('/get-blog/:id', async (req, res) => {
  try {
    const blog = await Blog.findById(req.params.id);
    if (!blog) {
      return res.status(404).json({ message: '博客不存在' });
    }
    // 把Delta转成HTML
    const htmlContent = quillRender(blog.contentDelta);
    res.json({
      title: blog.title,
      contentHtml: htmlContent,
      createdAt: blog.createdAt
    });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

6. 前端展示博客内容

拿到后端返回的 HTML 后,直接插入页面即可:

async function loadBlog(blogId) {
  const res = await fetch(`/api/get-blog/${blogId}`);
  const data = await res.json();
  document.getElementById('blog-title').textContent = data.title;
  document.getElementById('blog-content').innerHTML = data.contentHtml;
}

三、几个重要的注意事项

  • XSS 防护:用户输入的内容可能包含恶意脚本,一定要在渲染前过滤!可以用 xss 包对生成的 HTML 进行处理:const safeHtml = xss(htmlContent);
  • Quill 版本兼容:前后端尽量用相同版本的 Quill 和 quill-render,避免 Delta 格式不兼容导致渲染错误
  • 图片存储优化:如果博客访问量较大,建议用云存储(OSS、Cloudinary等)代替本地存储,更稳定也方便扩容
  • 备份 Delta:尽量一直存储 Delta 格式,而不是只存渲染后的 HTML,这样以后如果需要修改编辑器或者换渲染方式,都能灵活处理

内容的提问来源于stack exchange,提问作者Sam Min Wong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:16:08