2025-12-18-前端画布设计Vol.2 实现富文本编辑
1537 个字
8 分钟
2025-12-18-前端画布设计Vol.2 实现富文本编辑
画布项目中富文本编辑器的实现浅析
0x00 概述
该画布项目采用 wangEditor(v5 版本)的 React 封装组件 @wangeditor/editor-for-react 实现富文本编辑功能。主要通过两个组件协作完成:
- RichTextEditor.tsx:核心富文本编辑器封装,负责工具栏和编辑区的渲染与配置。
- BottomTextEditor.tsx:底部面板式编辑器,仅在选中单个文本元素时显示,将富文本编辑器集成到画布操作流程中,支持实时更新元素内容并记录撤销/重做操作。
主要形式是一个底部面板,单击文本元素会出现
0x01 RichTextEditor 组件实现
RichTextEditor 是对 wangEditor 的二次封装,提供可复用的富文本编辑器
import "@wangeditor/editor/dist/css/style.css";import { useState, useEffect } from "react";import { Editor, Toolbar } from "@wangeditor/editor-for-react";
const toolbarConfig: Partial<IToolbarConfig> = { toolbarKeys: [ "bold", "italic", "underline", "through", "|", "fontSize", "fontFamily", "color", "bgColor", "|", "justifyLeft", "justifyCenter", "justifyRight", "|", "undo", "redo", ],};
const editorConfig: Partial<IEditorConfig> = { placeholder: "请输入文本...", autoFocus: true,};
useEffect(() => { return () => { if (editor == null) return; editor.destroy(); setEditor(null); };}, [editor]);
return ( <div className="..."> <Toolbar editor={editor} defaultConfig={toolbarConfig} mode="simple" /> <Editor defaultConfig={editorConfig} value={value} onCreated={setEditor} onChange={(editor) => onChange(editor.getHtml())} mode="simple" style={{ height: "200px", overflowY: "auto" }} /> </div>);- 工具栏配置(toolbarConfig) 通过 toolbarKeys 指定显示的菜单键(加粗、斜体、下划线、删除线、字体大小/家族、颜色、背景色、对齐方式)以及撤销/重做。
- 编辑器配置(editorConfig) 设置占位符和自动聚焦。wangEditor 支持更丰富的配置(如最大长度、自定义菜单等),此处保持最小化。
- 生命周期管理 使用 useEffect 在组件卸载或 editor 实例变化时调用 editor.destroy(),防止内存泄漏。
- 内容同步value props 控制初始 HTML,onChange 回调通过 editor.getHtml() 获取最新 HTML 内容并向上通知。
0x02 BottomTextEditor 组件实现
BottomTextEditor 将富文本编辑器集成到画布状态管理中,仅针对选中单个文本元素时激活。
const { selectedIds, elements, updateElement } = useStore();
const selectedId = selectedIds.length === 1 ? selectedIds[0] : null;const element = selectedId ? elements[selectedId] : null;
const [localHtml, setLocalHtml] = useState("");
useEffect(() => { if (element && element.type === "text") { setLocalHtml(element.text || ""); }}, [element?.id, element?.text]);
const handleChange = (html: string) => { setLocalHtml(html); const initialText = element.text || ""; updateElement(element.id, { text: html });
const updateCommand = new UpdateElementPropertyCommand( { id: element.id, property: "text", oldValue: initialText, newValue: html }, "修改文本内容" ); undoRedoManager.executeCommand(updateCommand);};
return ( <div className="fixed bottom-8 ... animate-slide-up"> <RichTextEditor value={localHtml} onChange={handleChange} /> </div>);- 选中元素判断 从 Zustand store(canvasStore)获取选中 ID 和元素集合,仅当选中单个文本类型元素时渲染编辑器。
- 本地状态(localHtml) 使用 useState 维护本地 HTML 副本,并在选中元素变化时通过 useEffect 同步 store 中的 element.text。 此设计主要解决中文输入法(IME)组成阶段的问题:在拼音输入过程中,wangEditor 的 onChange 会频繁触发,若直接更新全局 store,可能导致输入延迟、光标跳动或内容混乱。通过本地状态缓冲实时变化,避免不必要的 store 更新。
- 内容变更处理(handleChange)
- 更新本地状态。
- 实时调用 updateElement 更新画布 store,驱动 canvas 重新渲染文本元素。
- 创建 UpdateElementPropertyCommand 命令并执行,支持撤销/重做(undo/redo)。命令记录旧值和新值,处理历史操作
0x03 关键问题解决与设计
- 输入法兼容性 中文输入过程中,组成事件(composition)会多次触发编辑器变更。若直接在 onChange 中更新全局状态,可能导致性能问题或输入体验不佳。本实现通过本地状态缓冲 setLocalHtml(html) 缓解该问题
- 实时渲染与历史管理 实时更新 store 确保画布文本即时反映变更;同时通过命令模式记录操作,实现完整的 undo/redo 支持。
0x04 当前实现的风险与不足分析
当前实现虽已满足基础富文本编辑需求,但是还是有一些问题
- 输入法体验优化不彻底 虽通过本地状态缓冲缓解了 IME 组成阶段的频繁更新问题,但未监听 compositionstart/compositionend 事件。在某些极端输入场景(如快速切换输入法或长句输入)下,仍可能出现光标偏移或临时内容丢失的现象。
- 内容净化与 XSS 防护不足 完全依赖 wangEditor 内置的有限转义机制,未引入 DOMPurify 等专用净化库。在用户插入外部链接、图片或自定义 HTML 时,存在潜在的存储型或 DOM 型 XSS 风险,尤其在内容后续导出或分享场景中。
- 样式与对齐精度问题 wangEditor 生成的 HTML 结构(如多层 span/div 嵌套)与画布自定义文本渲染逻辑可能不完全匹配,导致编辑器中预览效果与画布最终渲染存在细微差异(如行高、字间距、对齐方式)。
- 性能与内存管理 频繁的实时更新(onChange 触发 store 更新与命令记录)在长文本场景下可能导致轻微卡顿;此外,未对编辑器实例进行复用,当快速切换不同文本元素时会反复创建/销毁实例,增加内存开销。
面对这些问题后续都可以做一些改进:
- 引入 DOMPurify 进行内容净化来处理 XSS 问题 在内容存储前(提交到 store 或后端)及渲染时统一调用 DOMPurify.sanitize,对 HTML 进行严格过滤。自定义白名单以保留 wangEditor 支持的必要标签与属性,同时移除所有事件处理器及危险协议。
- 完善输入法兼容性 在 RichTextEditor 中监听 composition 事件,在组成阶段暂不触发 handleChange,仅在 compositionend 后统一更新 store 与命令记录,进一步消除输入延迟与光标问题。
- 性能优化 实现编辑器实例复用(单一全局实例,根据选中元素动态切换内容),并在长文本时增加防抖处理,减少不必要的 store 更新与命令执行。
0x05 总结
主要就是 wangEditor 的 React 封装,结合 Zustand 状态管理和命令模式,来适配画布类项目的文本编辑需求,实现了基础的文本编辑功能
分享到社交平台
将本文分享给你的朋友们
2025-12-18-前端画布设计Vol.2 实现富文本编辑
https://firefly.cuteleaf.cn/posts/2025-12-27-前端画布设计vol-2-实现富文本编辑/ 相关文章 智能推荐
1
2025-12-17-前端画布设计Vol.1 实现基础元素渲染和状态控制
前端 2025-12-28
2
2025-12-28-前端学习-接口类型定义、Axios 封装与请求规范
前端 2025-12-29
3
2025-11-23-前端学习-身份验证管理-基于 JWT Token 的实现
前端 2025-11-23
4
2026-01-24-前端开发速查单
前端 2026-01-24
5
2025-11-27-前端安全-关于XSS与CRSF及其相关对策
前端 2025-11-28
随机文章 随便看看
Zhongye