canvas富文本编辑器核心是将文本转为结构化字符数据并逐帧渲染,不依赖dom或contenteditable,适合强排版控制场景;数据以字符粒度json数组组织,含样式与换行符;需手动布局、测量宽度、换行计算、背景及装饰线绘制;交互通过鼠标定位与键盘事件驱动光标;支持分页模拟与导出。

用 Canvas 实现富文本编辑器,核心不是操作 DOM,而是把文本当作“可绘制的图形对象”来管理——每个字符或段落都转为结构化数据,再由 Canvas 2D 上下文逐帧渲染。它不依赖 contenteditable,适合对排版、分页、导出 PDF 或离线渲染有强控制需求的场景。
数据结构设计:以字符粒度组织样式
Canvas 编辑器不解析 HTML,而是使用扁平化的 JSON 数组描述内容,每个元素代表一个字符(或换行符),附带独立样式:
- value:单个字符或 '\n';不能是整段字符串,否则无法精确定位光标和选区
- color / background / size / fontfamily:基础文字样式
- bold / italic / underline / linethrough:开关类格式
- lineheight:按行高倍数设置,用于计算多行垂直间距
例如“理想”二字加粗、“青年”斜体,数据形如:[{value:'理',bold:true},{value:'想',bold:true},{value:'\n'},{value:'青',italic:true},{value:'年',italic:true}]
渲染逻辑:手动布局 + 逐字符绘制
Canvas 没有自动换行或流式布局,需自己实现:
- 用 context.font 动态设置当前字符字体(如
'bold 16px SimSun') - 调用 context.measureText(char).width 获取单字符宽度,累加判断是否超出页宽
- 遇到 '\n' 或行满时换行,y 坐标 += 当前行高(
fontSize × lineheight) - 对带背景色的文字,先用 context.fillRect() 绘制底色矩形,再 fillText()
- 下划线/中划线/删除线需手动计算 y 坐标并用 strokeRect() 或 beginPath()+lineTo() 绘制
交互支持:光标与键盘事件驱动
Canvas 本身不可聚焦,需主动接管输入逻辑:
- 监听 mousedown,用
getBoundingClientRect()和鼠标 clientX/Y 反推点击落在哪一行哪一列,确定插入位置 - 维护一个 cursorIndex,表示当前光标在数据数组中的索引位置
- 监听 keydown:Enter 插入 '\n';Backspace/Delete 删除前/后字符;普通字母数字插入到 cursorIndex 处
- 每次变更后清空画布(
ctx.clearRect(0,0,canvas.width,canvas.height)),重新 render 全量数据 - 用 setInterval 控制光标闪烁(draw / clear 矩形)
页面模拟:分页与打印友好结构
为贴近 Word 体验,需模拟纸张:
- 定义 pageWidth=794px(A4 宽)、pageHeight=1123px(A4 高)
- 每页 canvas 单独创建,通过 pagePadding(如 [100,120,100,120])预留页边距
- 在四角绘制 35×35px 直角折线,提示可视区域边界
- 页面间留 pageMargin=20px 空隙,滚动时视觉分离清晰
- 导出为图片或 PDF 时,可直接遍历 pageCanvasList.toDataURL() 或用 jsPDF 批量插入
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











