# 座位布局性能优化说明 ## 问题描述 当座位布局节点数量很大时(例如 50x50 = 2500 个单元格),会出现明显的卡顿现象。主要原因是: 1. **大量 DOM 节点**:双重循环渲染所有单元格,创建大量 DOM 元素 2. **重复计算**:每次渲染时,`getCellClass`、`getCellText`、`shouldRenderCell` 等函数都会被调用,且内部包含循环遍历 3. **查找性能**:使用 `Array.find()` 查找单元格,时间复杂度为 O(n) 4. **事件处理**:鼠标移动事件触发频繁,没有有效节流 ## 优化方案 ### 1. 使用 Map 缓存单元格查找 **优化前:** ```typescript const getCell = (col: number, row: number) => { return cells.value.find((c) => c.col === col && c.row === row); }; ``` **优化后:** ```typescript // 单元格查找缓存 Map: key = "col,row", value = cell const cellMapCache = ref>(new Map()); const getCell = (col: number, row: number) => { const key = `${col},${row}`; return cellMapCache.value.get(key); }; ``` **效果:** 查找时间复杂度从 O(n) 降低到 O(1) ### 2. 缓存合并单元格映射关系 **优化前:** ```typescript // 每次都要遍历所有单元格检查是否被合并 for (const otherCell of cells.value) { // ... 检查逻辑 } ``` **优化后:** ```typescript // 合并单元格主单元格映射: key = "col,row" (被合并的单元格), value = "col,row" (主单元格) const mergeMasterMapCache = ref>(new Map()); // 使用缓存检查 const key = `${col},${row}`; if (mergeMasterMapCache.value.has(key)) { return 'cell cell-merged'; } ``` **效果:** 避免了每次渲染时的 O(n²) 循环嵌套 ### 3. 使用 shallowRef 优化响应式性能 **优化前:** ```typescript const cells = ref([]); ``` **优化后:** ```typescript const cells = shallowRef([]); ``` **效果:** 减少深度响应式监听,提升性能 ### 4. 使用 requestAnimationFrame 优化鼠标移动事件 **优化前:** ```typescript mouseEnterTimer = window.setTimeout(() => { // 填充逻辑 }, 16); ``` **优化后:** ```typescript rafId = requestAnimationFrame(() => { // 填充逻辑 }); ``` **效果:** 与浏览器渲染周期同步,更流畅 ### 5. 使用 v-memo 指令缓存单元格渲染 **优化后:** ```vue
``` **效果:** 只有当依赖项变化时才重新渲染,减少不必要的 DOM 更新 ### 6. 统一更新缓存机制 在所有修改单元格的操作后,统一调用 `updateCellMapCache()` 更新缓存: - `initLayout()` - 初始化布局 - `loadLayout()` - 加载布局 - `addColumnLeft/Right()` - 添加列 - `addRowTop/Bottom()` - 添加行 - `mergeCells()` - 合并单元格 - `unmergeCell()` - 取消合并 - `handleUndo()` - 撤销操作 - `handleCellMouseUp()` - 鼠标释放 ## 性能提升 经过优化后,预期性能提升: 1. **单元格查找**:从 O(n) 降低到 O(1),查找速度提升 100-1000 倍(取决于单元格数量) 2. **合并检查**:从 O(n²) 降低到 O(1),检查速度提升 10000 倍以上 3. **渲染性能**:使用 v-memo 后,只有变化的单元格才会重新渲染 4. **鼠标交互**:使用 requestAnimationFrame 后,交互更流畅,帧率更稳定 ## 注意事项 1. **缓存一致性**:所有修改单元格的操作都必须调用 `updateCellMapCache()` 保持缓存同步 2. **内存占用**:Map 缓存会占用额外内存,但对于性能提升是值得的 3. **兼容性**:`v-memo` 是 Vue 3.2+ 的特性,确保项目使用 Vue 3.2 或更高版本 ## 后续优化建议 如果性能仍然不够理想,可以考虑: 1. **虚拟滚动**:只渲染可见区域的单元格(对 Grid 布局实现较复杂) 2. **Canvas 渲染**:使用 Canvas 替代 DOM 渲染(需要重写交互逻辑) 3. **Web Worker**:将复杂计算移到 Web Worker 中 4. **分块渲染**:将大布局分成多个块,按需加载