[插件] Vditor 编辑器(vditor)插件发布,可以在官网试一下。

👑Lv.11 元老 🌞 骨干会员
2026-10-20 13:32:45

https://www.flinthub.top/plughub/vditor

已经发布,用户后台安装体验即可

用 Vditor 4.0.1(MIT)替换核心富文本编辑器。
纯插件实现,不改核心一行代码;关掉插件即完全回退,已发布内容不受影响。


一、它做了什么

项 说明
替换范围 后台可逐个勾选:发帖 / 回复 / 博客 / 私信 / 后台编辑 / 插件页面
编辑器能力 即时渲染(IR)、所见即所得(WYSIWYG)、分屏(SV)三种模式;大纲、表格、代码高亮、全屏、字数统计、全套快捷键
数据格式 提交的仍是 base64(HTML),与核心编辑器完全一致 —— 服务端零改动
兼容层 提供 window.ACTIVE_EDITORS,draft_saver(草稿)、notice_center、qa 等依赖它的插件照常工作
上传 走核心 POST /api/upload?ajax=1,沿用核心的权限、CSRF、限流、缩略图规则

二、⚠️ 已知取舍(先读这段)

Vditor 是 Markdown 编辑器,而本站存的是 HTML。两者不是无损互转,以下格式会丢:

格式 结果 原因
字体颜色 / 背景色 ❌ 不提供 Markdown 无对应语法
段落对齐(左/中/右) ❌ 不提供 同上
合并单元格(colspan/rowspan) ❌ 不提供 核心净化白名单无该属性
任务列表(勾选框) ❌ 不提供 白名单无 <input>
录音 / 数学公式 / 流程图 ❌ 不提供 白名单无 <audio> / <math> / <svg>
一级标题 h1 ⚠️ 默认关闭 白名单只放行 h2~h4,开了会「发布后降级成正文」

设计原则:不提供「点了会坏」的按钮。所有 Markdown 表达不了的格式,在工具栏层面就不存在。

编辑历史帖子时:插件会做一次真实的「HTML → Markdown → HTML」往返比对
(用 Vditor 自带的 lute 引擎跑,不是猜的)。差异率超过阈值(后台可配,默认 15%)
→ 编辑器上方出现黄色提示条 + 「改用源码模式」按钮。

源码模式不是 Vditor 的 SV 分屏(SV 编辑的仍是 Markdown,格式该丢还是丢)。
提示条给的是插件自己实现的 HTML 源码模式:一个直接装原始 HTML 的 textarea,
提交时逐字节原样交给服务端 → 真正无损。改完点「返回可视化编辑」会重新转成 Markdown。
工具栏里本来就有 Vditor 的 edit-mode 按钮可切 IR / WYSIWYG / SV,所以提示条不重复提供。


三、构建产物

运行文件已随包提供,位于:

plugins/vditor/assets/lib/vditor/dist/
├── index.min.js                          296 KB   webpack 主包
├── index.css                              48 KB
├── js/lute/lute.min.js                   3.57 MB   Markdown↔HTML 引擎(硬依赖)
├── js/highlight.js/highlight.min.js      1.03 MB   代码高亮
├── js/highlight.js/third-languages.js      21 KB
├── js/highlight.js/styles/{github,github-dark}.min.css
├── js/icons/ant.js                        42 KB
├── js/i18n/{zh_CN,zh_TW,en_US}.js
├── css/content-theme/{light,dark}.css
└── images/emoji/*.png

合计 30 个文件 / 约 5.04 MB。

自己重新构建(升级 Vditor 时)

cd D:\phpstudy_pro\WWW\vditor-4.0.1

# 1) 装依赖(跳过 puppeteer 的 Chromium 下载,构建不需要它)
$env:PUPPETEER_SKIP_DOWNLOAD = '1'
npm install --legacy-peer-deps

# 2) 构建
npm run build

# 3) 裁剪 + 转 LF / 去 BOM + 落到插件目录
php ..\.workbuddy-ai\tmp\vditor_trim.php

两个必须的依赖修正(已写进 vditor-4.0.1/package.json,重装不会丢):

包 值 原因
ajv ^8.17.1 上游用 pnpm(不强制 peer),npm 下 ajv-keywords@5 会解析到 ajv 6 → 构建报 Cannot find module 'ajv/dist/compile/codegen'
@types/diff-match-patch 1.0.32(锁死) 1.0.36 把声明改成 export = 形式 → src/ts/undo/index.ts 报 TS2749

只裁剪 dist 里的白名单文件,不要整个 dist 拷过去(全量 21.9 MB,含 mathjax 6.3 MB / mermaid 3.4 MB 等用不到的重货)。


四、后台配置

入口:后台 → 插件 → Vditor 编辑器(/admin/vditor)

项 默认 说明
启用 Vditor 编辑器 关 总开关。关掉立即全站回退核心编辑器
发帖 / 编辑帖子 开 post/create、post/edit、thread/edit
帖子回复 开 thread/show
博客 / 私信 / 后台编辑 关 按需开
插件页面 关 问答 / 网盘 / 单页 / 投稿 / 公告。建议最后再开
默认编辑模式 IR IR 最接近原可视化体验;SV 适合写源码
发帖 / 回复高度 560 / 320 160~2000
代码高亮主题 跟随主题 浅色页用 github、深色页用 github-dark。站点同时有浅色/暗色用户时保持这一项
格式损失提示阈值 15% 0 = 关闭探测
允许一级标题 关 关时 h1 自动降成 h2(白名单没有 h1)

五、生效条件(三者必须同时满足)

  1. 插件已激活
  2. 总开关已开启
  3. 构建产物完整(Plugin::libReady() 检查 4 个关键文件)

任一不满足 → 所有钩子早退,核心编辑器照常工作(Fail-Safe)。
编辑器是「增强」不是「门禁」,绝不允许因为插件没配好就让人发不了帖。

后台设置页顶部会用红/黄条明确告诉你差哪一项。


六、常见问题

Q:装上之后发帖页没变化?
A:检查后台状态徽章。三个条件任一未满足都会这样,页面顶部有具体原因。

Q:为什么颜色/对齐按钮没了?
A:见第二节。这是刻意的设计取舍,不是 bug。

Q:历史帖子里的彩色文字打开编辑后变黑白了?
A:Markdown 无法表达颜色。如果差异超阈值会有黄色提示条,点「切换到源码模式」可保留原始 HTML。

Q:草稿插件还能用吗?
A:能。插件提供了 window.ACTIVE_EDITORS 兼容层,读写都走 Vditor 的 API。

Q:控制台报 404 / 被 CSP 拦截?
A:检查 plugins/vditor/assets/lib/vditor/dist/ 是否完整;options.cdn 已强制指向站点同源路径,不会请求外网。

Q:为什么公式显示成原始的 $x^2$?
A:KaTeX 有 326 KB JS + 1 MB 字体,没随包带(会让体积从 5 MB 涨到 6.4 MB)。所以公式渲染是关掉的,
不会去请求不存在的 /dist/js/katex/(那才是真 404)。要公式就把 Vditor 完整 dist 里的
js/katex/ 拷进 dist/js/,再把 assets/boot.js 里的 math: { engine: '' } 改成 math: { engine: 'KaTeX' }。

Q:为什么没有「代码主题」切换按钮?
A:Vditor 那个面板列的是它自带的全部 ~90 个主题 CSS,我们只带了 github / github-dark 两份 ——
放了就是「点别的必 404」。主题在后台选,不在前台切。

Q:mermaid / 流程图 / 脑图能渲染吗?
A:不能,同样没带产物(mermaid 3.4 MB、graphviz 1.9 MB…)。这类代码块会原样显示成代码,不会报错。

Q:能只对发帖开、回复不开吗?
A:可以,页面开关互相独立。


七、实现要点(改代码前必读)

环节 做法 为什么
关掉核心编辑器 controller_view_before 里置 $data['needsEditor'] = false 该钩子的 $data 是引用(Controller.php:49 的 &$data + EXTR_REFS)→ 能真的改到控制器里的数组
跨钩子传状态 Plugin::markActive() 写类静态属性 钩子在闭包作用域里 include,变量传不出去,只有类静态可靠
回填已有内容 挂载前先写 mount.innerHTML initUI.ts:9 第一行就清空宿主;originalInnerHTML 在 init() 里已捕获,afterRender 会 HTML2Md() —— 无时序竞态
关掉草稿缓存 cache: { enable: false } 默认 true,initUI.ts:173 先读 localStorage → 会盖掉回填的旧内容
只引 1 个 JS 只写 index.min.js lute / i18n / icons / highlight 都由 Vditor 自己按 options.cdn 加载;手写会重复加载
同步脚本 index.min.js 在 head 同步、boot.js 在 body 末尾同步 defer 要等解析完才跑,boot.js 会先执行 → 那时 window.Vditor 还没定义
ACTIVE_EDITORS detached 假节点 + defineProperty 接管 innerHTML draft_saver 会 ed.editor.innerHTML = ... 直接赋值;给真实 DOM 会绕过 Vditor 内部模型(表面有字、getHTML() 还是旧的)
提交格式 base64(UTF-8 bytes) 写进同名隐藏域 与 editor.js:1113 完全一致,Content::decode() 零改动
引用功能 重写 window.quotePost 核心 editor.js 不加载 → 原实现不存在
写设置 Settings::get/update 绝不能传null 两个签名都是非可空 string(Settings.php:31/255)。userland 函数传 null 直接 TypeError,而核心 Plugin::activate() 是 catch (\Throwable) 静默回滚 → 后台只显示「启用失败」、零日志。判「键是否存在」用哨兵串;卸载清空写空串(Settings 没有 delete)
校验 CSRF Csrf::verifyOrDie($_POST['csrf'] ?? '') Csrf::verifyOrDie($token) 是必填 1 参(Csrf.php:60)。写成无参 → ArgumentCountError → 保存接口 500

已带的产物之外都是关的:KaTeX(math.engine='')、mermaid / graphviz / echarts / plantuml /
markmap / SMILES / wavedrom(无产物时 Vditor 只是不渲染,不会抛错)。


八、许可

  • Vditor 4.0.1:MIT,Copyright (c) 2018-present B3log 开源
  • 插件本体:与 FlintHub 一致
最后由 flinthub 于 2026-10-20 13:35 编辑
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 9 次 | 回复 1 次

全部回复 (1)

👑Lv.11 元老 🌞 骨干会员
2026-10-20 13:39:09

手机试一下回复可以吗

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
#1 楼

请 登录