# 图标重排与持久化
**Referenced Files in This Document **
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts)
- [DesktopContainer.vue](file://src/ui/desktop-container/DesktopContainer.vue)
- [IDesktopAppIcon.ts](file://src/ui/types/IDesktopAppIcon.ts)
## 目录
1. [appIconsRef的创建过程](#appiconsref的创建过程)
2. [localStorage数据同步机制](#localstorage数据同步机制)
3. [网格变化监听与重排响应](#网格变化监听与重排响应)
4. [rearrangeIcons算法详解](#rearrangeicons算法详解)
5. [布局状态持久化策略](#布局状态持久化策略)
## appIconsRef的创建过程
`appIconsRef` 是一个 Vue 响应式引用,用于管理桌面图标的布局状态。其创建过程始于 `useDesktopContainerInit` 函数的调用,该函数接收容器选择器字符串作为参数并初始化核心布局逻辑。
在初始化过程中,系统首先从 `localStorage` 中读取键为 `desktopAppIconInfo` 的存储项,尝试恢复之前保存的图标位置信息。若存在历史数据,则解析为 `oldAppIcons` 数组;否则使用空数组作为默认值。随后,系统遍历当前可用的应用程序列表(`appInfos`),为每个应用创建对应的桌面图标对象。
对于每个新生成的图标,系统优先检查是否存在同名的历史图标记录。如果存在,则继承其坐标(x, y);若不存在,则根据当前网格的行列数按索引自动分配初始坐标:
- 列坐标 x = 当前索引 % 行数 + 1
- 行坐标 y = floor(当前索引 / 行数) + 1
最终,这些图标数据被封装为响应式引用 `appIconsRef`,供视图层绑定使用。
**Section sources**
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L74-L94)
## localStorage数据同步机制
系统通过双向数据绑定机制实现 `appIconsRef` 与 `localStorage` 的实时同步。当用户对桌面图标进行拖拽、重排等操作导致布局变更时,Vue 的响应式系统会触发相应的监听器,将最新状态持久化到本地存储中。
具体而言,系统注册了一个针对 `appIconsRef.value` 的 `watch` 监听器。每当图标数组内容发生变化(如新增、删除或位置调整),该监听器便会执行回调函数,将更新后的 `appIcons` 数组序列化为 JSON 字符串,并通过 `localStorage.setItem('desktopAppIconInfo', ...)` 方法写入浏览器本地存储。
此机制确保了用户在刷新页面或重新打开应用后,能够恢复上次关闭时的桌面布局,实现了跨会话的个性化配置记忆功能。
**Section sources**
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L89-L92)
## 网格变化监听与重排响应
为了适应不同屏幕尺寸和窗口大小的变化,系统利用 `ResizeObserver` API 实时监测桌面容器的尺寸变动,并动态计算最优的网格列数(`colCount`)和行数(`rowCount`)。当这些参数发生改变时,系统需要智能地重新排列所有图标以避免重叠或溢出。
为此,系统设置了一个复合监听器 `watch(() => [gridTemplate.colCount, gridTemplate.rowCount], ...)`, 专门监控 `colCount` 和 `rowCount` 的联合变化。一旦检测到新的网格维度,监听器立即调用 `rearrangeIcons` 函数,传入当前图标列表及新的行列限制,执行自动重排逻辑。
该监听器包含优化判断:若新旧行列数完全一致,则直接返回,避免不必要的重排计算,提升性能效率。
**Section sources**
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L86-L88)
## rearrangeIcons算法详解
`rearrangeIcons` 函数是整个图标管理系统的核心算法,负责处理图标冲突、寻找空闲位置以及管理超出可视范围的图标。其输入为原始图标数组和目标网格的最大行列数,输出为包含正常显示图标和隐藏图标的结构体。
### 冲突检测与占用标记
算法首先创建一个 `Set` 类型的 `occupied` 集合,用于记录已被占用的网格单元。通过辅助函数 `key(x, y)` 将二维坐标转换为唯一字符串标识(如 `"1,2"`),实现高效的哈希查找。
### 分阶段处理流程
1. **第一阶段:保留有效位置**
- 遍历所有图标,筛选出位于当前网格范围内的图标(即 `x ≤ maxCol && y ≤ maxRow`)
- 检查目标位置是否已被占用,若未占用则将其加入结果数组 `appIcons` 并标记为已占用
- 对于位置无效或冲突的图标,则暂存至临时数组 `temp`
2. **第二阶段:填补空位**
- 遍历 `temp` 数组中的待安置图标
- 若当前已放置图标数量小于网格总容量(`maxCol * maxRow`),则从左上角 `(1,1)` 开始逐行扫描,寻找第一个空闲位置进行安置
- 一旦找到合适位置,立即跳出内层循环,继续处理下一个图标
3. **第三阶段:处理溢出图标**
- 若网格已满且仍有剩余图标无法安置,则将其归类至 `hideAppIcons` 数组
- 这些图标将在 UI 层面被隐藏,防止界面混乱
```mermaid
flowchart TD
Start([开始重排]) --> ValidatePosition["验证图标位置有效性"]
ValidatePosition --> InRange{"是否在网格范围内?"}
InRange --> |是| CheckOccupied["检查位置是否被占用"]
InRange --> |否| ToTemp["加入临时数组 temp"]
CheckOccupied --> IsFree{"位置空闲?"}
IsFree --> |是| PlaceIcon["放置图标并标记占用"]
IsFree --> |否| ToTemp
PlaceIcon --> NextIcon["处理下一个图标"]
ToTemp --> NextIcon
NextIcon --> AllProcessed{"所有图标处理完毕?"}
AllProcessed --> |否| ValidatePosition
AllProcessed --> |是| FillEmpty["填补空位"]
FillEmpty --> HasSpace{"仍有空位?"}
HasSpace --> |是| FindSlot["从(1,1)开始寻找空位"]
HasSpace --> |否| HideExcess["隐藏超出图标"]
FindSlot --> CanPlace{"能否放置?"}
CanPlace --> |是| UpdateAppIcons["更新 appIcons 数组"]
CanPlace --> |否| HideExcess
UpdateAppIcons --> MoreTemp{"temp 数组为空?"}
MoreTemp --> |否| FillEmpty
MoreTemp --> |是| ReturnResult["返回结果: appIcons + hideAppIcons"]
HideExcess --> ReturnResult
```
**Diagram sources **
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L102-L156)
**Section sources**
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L102-L156)
## 布局状态持久化策略
系统的布局持久化策略建立在 Vue 的响应式系统与浏览器本地存储的协同工作之上。`appIconsRef` 作为单一数据源(Single Source of Truth),集中管理所有图标的坐标信息。任何对图标的修改操作(无论是用户交互还是程序逻辑)都会反映到该引用上。
通过 `watch` 监听器,系统实现了从内存状态到持久化存储的单向同步。这种设计具有以下优势:
- **自动同步**:无需手动调用保存方法,所有变更自动记录
- **原子性保证**:每次写入都是完整的数组快照,避免部分更新导致的数据不一致
- **跨会话恢复**:页面刷新后可通过 `localStorage.getItem('desktopAppIconInfo')` 重建初始状态
- **容错处理**:使用 `JSON.parse(... || '[]')` 确保解析失败时返回安全默认值
该策略构成了完整的“读取→运行→修改→保存”闭环,保障了用户体验的一致性和数据的安全性。
**Section sources**
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L89-L92)