You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3集成Fabric.js开发电子白板:书写200次后卡顿求助

Fabric.js电子白板书写200次后卡顿问题排查与优化

核心问题分析

你怀疑的这段代码确实是卡顿的核心诱因:每次绘制完成后都调用canvas.toJSON()全量序列化整个画布,随着路径数量突破200+,序列化的时间开销会线性增长;同时全量保存画布状态到历史记录会快速占用内存,触发频繁的垃圾回收,最终导致操作卡顿。

针对性优化方案

1. 替换全量序列化为增量记录

不要每次都序列化整个画布,只记录本次新增路径的状态,大幅减少计算开销:

this.canvas.add(pathObj)
// 仅序列化当前新增的路径,而非全画布
const pathState = pathObj.toJSON(['eventInfo'])
const action = {
  type: 'draw',
  data: pathState // 传递单个路径的增量数据
}
// 调整getState逻辑,基于现有状态合并增量
this.state = this.getState(this.state, action)
// 仅保存增量操作到历史,而非全量状态
this.saveHistory(action)

后续恢复历史时,基于初始状态逐个应用增量操作即可,避免全量序列化的性能损耗。

2. 合并连续手绘路径

Fabric.js中每个Path对象都会占用渲染资源,连续的手绘路径(比如一笔画的线条)可以合并成单个Path对象,减少画布上的对象总数:

// 示例:合并同属性的连续路径
const lastPath = this.canvas.getObjects().pop()
if (lastPath && lastPath.type === 'path' && lastPath.stroke === pathObj.stroke) {
  // 合并路径指令
  lastPath.path.push(...pathObj.path)
  lastPath.setCoords()
  this.canvas.renderAll()
  // 无需新增对象,直接更新历史记录
  return
}
// 不满足合并条件时再新增路径
this.canvas.add(pathObj)

3. 优化历史记录存储

放弃保存完整画布状态快照,改为存储操作指令(比如draw、delete、modify)及对应数据,历史记录的内存占用会骤降,同时回退/重做操作也更高效。

4. 渲染性能调优

  • 开启Fabric.js的preserveObjectStacking时注意控制层级,避免不必要的重排
  • 将静态PDF背景转为Image对象添加到画布底层,避免PDF渲染与手绘路径的性能冲突

调试建议

用浏览器DevTools的Performance面板录制卡顿场景,查看canvas.toJSON和saveHistory的执行耗时,确认是否是JS线程阻塞导致的卡顿;同时查看Rendering面板,检查是否有过度绘制的情况。

内容的提问来源于stack exchange,提问作者stchen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 13:28:29