Canvas富文本排版本质是字符级手动布局:以扁平JSON描述每个字符及控制符,JavaScript精确计算位置、样式与分页,图文公式等作为同级占位节点嵌入,支持多页纸张模拟与全局装饰层绘制。

Canvas 实现富文本画布混合排版,本质是放弃 DOM 流式布局,转为“字符即图形”的手动排版模型——每个文字、换行、背景块、装饰线都作为独立可计算的绘制单元,由 JavaScript 精确控制位置、样式与层级。
结构化数据组织:按字符粒度建模
不传 HTML 或整段字符串,而是用扁平 JSON 数组描述内容,每个元素代表一个字符或控制符:
-
value 字段存单个字符(如
'A')或'\n',确保光标能精确定位到任意字节位置 - 样式字段直接挂载:如
color、size、fontfamily、bold、underline、background - 段落级属性如
lineheight(倍数)、align(left/center/right)单独标记在换行前或段首元素上
逐帧渲染逻辑:从左到右、从上到下手工布局
Canvas 没有自动换行,所有排版必须自己算:
- 设置当前字符的
ctx.font(例如'bold 16px "PingFang SC"'),再调用ctx.measureText(char).width累加宽度 - 遇到
'\n'或宽度超出行宽(扣除左右页边距后)时,y 坐标 += 当前行高(fontSize × lineheight),x 归零 - 带背景色的文字:先
ctx.fillRect(x, y - ascent, width, height)(需用ctx.font和ctx.textBaseline推算基线偏移),再fillText() - 下划线/删除线:根据字体度量(如
ascent、descent)计算 y 坐标,用beginPath() + moveTo() + lineTo()绘制细线
混合排版关键:图文/控件/公式等非文本元素嵌入
把图片、表格、数学公式、签名框等视为“占位符节点”,和字符同级存在数据数组中:
立即学习“前端免费学习笔记(深入)”;
- 类型标识如
{ type: 'image', src: '...', width: 200, height: 120, align: 'center' } - 渲染时跳过
fillText,改用ctx.drawImage()或递归绘制子 Canvas(如公式用 KaTeX 渲染到离屏 canvas 再贴图) - 表格用嵌套结构表示行列,每单元格当作独立文本块+边框矩形,支持跨行跨列通过坐标偏移模拟
- 控件(如复选框、日期输入)渲染为静态外观,交互区域通过
isPointInPath()或坐标范围判断触发编辑态
页面级结构:模拟真实纸张与多页衔接
为支撑打印与导出,需构建分页上下文:
- 定义固定纸张尺寸(如 A4:794×1123 px),设定上下左右内边距(如
[100, 120, 100, 120]) - 渲染时按页切割数据流:维护当前页剩余可用高度,当 y 超出页底且下一个元素无法放下时,插入分页符并重置 y 到下一页顶部
- 页眉页脚单独维护数据数组,在每页起始/结束处调用对应 render 函数;页码用
currentPage动态生成 - 四个角的直角折线、水印、背景图等,均作为 canvas 全局装饰层在主内容之下绘制



















