Files
booking_admin/doc/座位布局性能优化说明.md
杨志 8e308a75f6
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
修改布局,修复BUG
2025-12-08 11:49:09 +08:00

143 lines
4.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 座位布局性能优化说明
## 问题描述
当座位布局节点数量很大时(例如 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<Map<string, ClassroomApi.ClassroomLayoutCell>>(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<Map<string, string>>(new Map());
// 使用缓存检查
const key = `${col},${row}`;
if (mergeMasterMapCache.value.has(key)) {
return 'cell cell-merged';
}
```
**效果:** 避免了每次渲染时的 O(n²) 循环嵌套
### 3. 使用 shallowRef 优化响应式性能
**优化前:**
```typescript
const cells = ref<ClassroomApi.ClassroomLayoutCell[]>([]);
```
**优化后:**
```typescript
const cells = shallowRef<ClassroomApi.ClassroomLayoutCell[]>([]);
```
**效果:** 减少深度响应式监听,提升性能
### 4. 使用 requestAnimationFrame 优化鼠标移动事件
**优化前:**
```typescript
mouseEnterTimer = window.setTimeout(() => {
// 填充逻辑
}, 16);
```
**优化后:**
```typescript
rafId = requestAnimationFrame(() => {
// 填充逻辑
});
```
**效果:** 与浏览器渲染周期同步,更流畅
### 5. 使用 v-memo 指令缓存单元格渲染
**优化后:**
```vue
<div
v-if="shouldRenderCell(col - 1, row - 1)"
v-memo="[getCell(col - 1, row - 1)?.type, getCell(col - 1, row - 1)?.status, ...]"
:class="getCellClass(col - 1, row - 1)"
...
>
```
**效果:** 只有当依赖项变化时才重新渲染,减少不必要的 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. **分块渲染**:将大布局分成多个块,按需加载