乐于分享
好东西不私藏

富文本编辑器wangEditor (v5) 在 Spring Boot_Thymeleaf 项目中的使用流程

富文本编辑器wangEditor (v5) 在 Spring Boot_Thymeleaf 项目中的使用流程

富文本编辑器在“新增”和“修改”两种场景下的流程,一般是“引入资源 → 搭建结构 → 初始化 → 数据同步”。

第一步:引入资源

无论是添加还是编辑页面,首先必须引入 CSS 和 JS 文件。

  • CSS: 决定编辑器的长什么样(边框、按钮样式)。
  • JS: 决定编辑器能做什么(核心逻辑)。
<link rel="stylesheet" th:href="@{/js/wangEditor.min.css}"><script th:src="@{/js/wangEditor.min.js}"></script>

第二步:构建 HTML 结构

wangEditor v5 推荐将 工具栏 和 编辑区 分离,以便更灵活地控制布局。

  1. 外层容器 (#editor-wrapper): 控制整体高度(如 500px)和边框。
  2. 工具栏容器 (#toolbar-container): 放置加粗、斜体等按钮。
  3. 编辑容器 (#editor-container): 用户输入内容的区域,通常设置 overflow-y: auto 实现内容滚动。
  4. 隐藏域 textarea关键点。编辑器本身不是表单控件,需要这个隐藏域来存储数据,以便随表单提交。

第三步:CSS 样式控制

通过 CSS 精确控制高度,防止工具栏遮挡内容或高度溢出。

  • 核心公式#editor-container 的高度 = #editor-wrapper 总高度 – 工具栏高度。
  • 代码示例:height: calc(100% - 40px);

第四步:JavaScript 初始化

这是核心逻辑,分为“配置”和“创建”两个动作。

1. 配置 (editorConfig)

  • placeholder: 提示文字。
  • onChange数据同步的核心。每当用户输入内容,触发此事件,将编辑器的 HTML 内容实时赋值给隐藏的 <textarea>

2. 创建 (createEditor & createToolbar)

  • 使用 createEditor 绑定编辑区 DOM。
  • 使用 createToolbar 绑定工具栏 DOM,并关联编辑器实例。

第五步:数据交互 (添加 vs 编辑)

这是你提供的两段代码最大的区别所在,也是实际开发中最容易出错的地方。

场景 A:添加页面 (数据写入)

  • 初始内容: 默认为空或 <p><br></p>

  • 目标: 用户输入内容 -> 同步到隐藏域 -> 提交给后端。

  • 代码逻辑:

    html: '<p><br></p>' // 默认为空

场景 B:编辑页面 (数据回填 + 更新)

  • 初始内容必须从后端获取

  • 目标: 后端数据 -> 填充到编辑器 -> 用户修改 -> 同步 -> 提交。

  • 关键技术: 使用 Thymeleaf 语法 [[${...}]] 将后端对象属性注入到 JS 中。

  • 代码逻辑:

    // 如果后端有数据则显示,否则显示空行html: [[${meetingJl.hynr}]] || '<p><br></p>',

    注意: 这里的 meetingJl.hynr 是后端传过来的富文本 HTML 字符串。


第六步:表单提交

在点击“保存”按钮时(submitHandler),必须确保隐藏域中的数据是最新的。

  1. 校验: 检查表单其他字段是否合法。
  2. 强制同步: 虽然 onChange 已经做了同步,但在提交瞬间再次执行 $('#hynr').val(editor.getHtml()) 是最稳妥的做法。
  3. 提交: 使用 AJAX 或表单默认行为提交数据。
functionsubmitHandler() {if ($.validate.form()) {        // 1. 获取最新内容        var htmlContent = editor.getHtml();        // 2. 放入隐藏域        $('#hynr').val(htmlContent);        // 3. 提交表单        $.operate.save(prefix + "/edit", $('#form-jl-edit').serialize());    }}

总结对照表

步骤
添加页面
编辑页面
HTML 结构
相同 (Wrapper + Toolbar + Editor + Textarea)
相同
初始化内容 html: '<p><br></p>'

 (空)
html: [[${entity.field}]]

 (后端数据回填)
数据流向
用户 -> 编辑器 -> 隐藏域 -> 后端
后端 -> 编辑器 -> 用户修改 -> 隐藏域 -> 后端
提交路径 /add /edit

参考代码:

添加页面:

    <link rel="stylesheet" th:href="@{/js/wangEditor.min.css}">    <style>        /* 1. 编辑器外层容器样式(包含工具栏和编辑区域) */#editor-wrapper {            border: 1px solid #ccc;            height: 500px; /* 总高度 */            z-index: 100;        }        /* 2. 工具栏样式 */#toolbar-container {            border-bottom: 1px solid #ccc; /* 工具栏底部边框 */            background-color: #f8f9fa; /* 工具栏背景色,可选 */        }        /* 3. 编辑区域样式(内容可滚动区域) */#editor-container {            height: calc(100% - 40px); /* 高度 = 总高度 - 工具栏高度(约40px) */            overflow-y: auto; /* 允许内容滚动 */            background-color: #fff;        }    </style>        <div class="form-group">            <label class="col-sm-3 control-label">会议内容:</label>            <div class="col-sm-8">                <!-- 注意:这里修改了结构,使用 wrapper 包裹 toolbar 和 editor -->                <div id="editor-wrapper">                    <!-- 工具栏容器 -->                    <div id="toolbar-container"></div>                    <!-- 编辑器容器 -->                    <div id="editor-container"></div>                </div>                <!-- 隐藏域用于表单提交 -->                <textarea name="hynr" id="hynr" style="display: none;"></textarea>            </div>        </div><!-- 引入 JS 文件 --><script th:src="@{/js/wangEditor.min.js}"></script><script th:inline="javascript">    var prefix = ctx + "system/jl";    var editor;    $(function () {if (typeof window.wangEditor === 'undefined') {            console.error('WangEditor 未加载,请检查文件路径');return;        }        // 解构赋值        const { createEditor, createToolbar } = window.wangEditor;        // 1. 编辑器配置        const editorConfig = {            placeholder: '请输入会议内容...',            onChange: (editor) => {            // 实时同步 HTML 到 textarea            $('#hynr').val(editor.getHtml());    }    };        // 2. 创建编辑器        // 注意:这里不再设置 height,由 CSS 控制高度        editor = createEditor({            selector: '#editor-container',            html: '<p><br></p>',            config: editorConfig,            mode: 'default'        });        // 3. 创建工具栏 (这才是官方 Demo 的标准模式)        const toolbar = createToolbar({            editor,            selector: '#toolbar-container',            config: {                // 这里可以配置工具栏的按钮组,如果不配置则显示默认全部                // excludeKeys: ['bold''italic'] // 例如:排除加粗和斜体            },            mode: 'default'        });    });functionsubmitHandler() {if ($.validate.form()) {if (editor) {                var htmlContent = editor.getHtml(); // 获取 HTML                console.log("准备发送的内容:", htmlContent); // <-- 加这一行                $('#hynr').val(editor.getHtml());            }            $.operate.save(prefix + "/add", $('#form-jl-add').serialize());        }    }</script>

编辑页面:

    <!-- 引入 CSS 文件 -->    <link rel="stylesheet" th:href="@{/js/wangEditor.min.css}">    <style>        /* 1. 编辑器外层容器样式(包含工具栏和编辑区域) */#editor-wrapper {            border: 1px solid #ccc;            height: 500px; /* 总高度 */            z-index: 100;        }        /* 2. 工具栏样式 */#toolbar-container {            border-bottom: 1px solid #ccc; /* 工具栏底部边框 */            background-color: #f8f9fa; /* 工具栏背景色,可选 */        }        /* 3. 编辑区域样式(内容可滚动区域) */#editor-container {            height: calc(100% - 40px); /* 高度 = 总高度 - 工具栏高度(约40px) */            overflow-y: auto; /* 允许内容滚动 */            background-color: #fff;        }    </style>        <div class="form-group">            <label class="col-sm-3 control-label">会议内容:</label>            <div class="col-sm-8">                <!-- 注意:这里修改了结构,使用 wrapper 包裹 toolbar 和 editor -->                <div id="editor-wrapper">                    <!-- 工具栏容器 -->                    <div id="toolbar-container"></div>                    <!-- 编辑器容器 -->                    <div id="editor-container"></div>                </div>                <!-- 隐藏域用于表单提交 -->                <!-- 修改:name 和 id 保持一致,用于 JS 赋值 -->                <textarea name="hynr" id="hynr" style="display: none;" th:field="*{hynr}"></textarea>            </div>        </div><!-- 引入 JS 文件 --><script th:src="@{/js/wangEditor.min.js}"></script><!-- 修改:添加 th:inline="javascript" 以支持后端数据注入 --><script th:inline="javascript">    var prefix = ctx + "system/jl";    var editor;    $(function () {if (typeof window.wangEditor === 'undefined') {            console.error('WangEditor 未加载,请检查文件路径');return;        }        // 解构赋值        const { createEditor, createToolbar } = window.wangEditor;        // 1. 编辑器配置        const editorConfig = {            placeholder: '请输入会议内容...',            onChange: (editor) => {            // 实时同步 HTML 到 textarea            $('#hynr').val(editor.getHtml());    }    };        // 2. 创建编辑器        // 注意:这里不再设置 height,由 CSS 控制高度        editor = createEditor({            selector: '#editor-container',            // 修改:从后端获取数据并赋值给编辑器            // [[${meetingJl.hynr}]] 是 Thymeleaf 语法,用于获取 Java 对象的属性            html: [[${meetingJl.hynr}]] || '<p><br></p>',            config: editorConfig,            mode: 'default'        });        // 3. 创建工具栏        const toolbar = createToolbar({            editor,            selector: '#toolbar-container',            config: {                // 这里可以配置工具栏的按钮组,如果不配置则显示默认全部                // excludeKeys: ['bold''italic'] // 例如:排除加粗和斜体            },            mode: 'default'        });    });functionsubmitHandler() {if ($.validate.form()) {if (editor) {                var htmlContent = editor.getHtml();                                 $('#hynr').val(htmlContent);            }            // 修改:提交路径改为 edit            $.operate.save(prefix + "/edit", $('#form-jl-edit').serialize());        }    }</script></body></html>