140 lines
7.0 KiB
Markdown
140 lines
7.0 KiB
Markdown
|
|
# 网格参数计算机制
|
|||
|
|
|
|||
|
|
<cite>
|
|||
|
|
**本文档引用文件**
|
|||
|
|
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts)
|
|||
|
|
- [DesktopContainer.vue](file://src/ui/desktop-container/DesktopContainer.vue)
|
|||
|
|
- [basic.css](file://src/css/basic.css)
|
|||
|
|
- [IGridTemplateParams.ts](file://src/ui/types/IGridTemplateParams.ts)
|
|||
|
|
</cite>
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
1. [引言](#引言)
|
|||
|
|
2. [核心数据结构定义](#核心数据结构定义)
|
|||
|
|
3. [ResizeObserver中的动态网格计算逻辑](#resizeobserver中的动态网格计算逻辑)
|
|||
|
|
4. [实际单元格尺寸的精确控制](#实际单元格尺寸的精确控制)
|
|||
|
|
5. [gridStyle样式对象的生成与绑定](#gridstyle样式对象的生成与绑定)
|
|||
|
|
6. [图标重排机制分析](#图标重排机制分析)
|
|||
|
|
7. [总结](#总结)
|
|||
|
|
|
|||
|
|
## 引言
|
|||
|
|
本项目通过Vue 3组合式API实现了一个响应式的桌面图标容器布局系统。其核心在于利用`ResizeObserver`监听容器尺寸变化,动态计算并调整CSS Grid布局的行列数及单元格大小。该机制确保在不同屏幕尺寸和窗口缩放情况下,桌面图标能够自适应排列,同时保持良好的视觉一致性与交互体验。
|
|||
|
|
|
|||
|
|
## 核心数据结构定义
|
|||
|
|
系统通过接口`IGridTemplateParams`定义了网格布局所需的核心参数集合:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
export interface IGridTemplateParams {
|
|||
|
|
readonly cellExpectWidth: number; // 预期单元格宽度
|
|||
|
|
readonly cellExpectHeight: number; // 预期单元格高度
|
|||
|
|
cellRealWidth: number; // 实际单元格宽度
|
|||
|
|
cellRealHeight: number; // 实际单元格高度
|
|||
|
|
gapX: number; // 列间距
|
|||
|
|
gapY: number; // 行间距
|
|||
|
|
colCount: number; // 总列数
|
|||
|
|
rowCount: number; // 总行数
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这些参数构成了整个动态网格计算的基础,其中预期尺寸为设计基准值,而实际尺寸则由运行时环境动态决定。
|
|||
|
|
|
|||
|
|
**Section sources**
|
|||
|
|
- [IGridTemplateParams.ts](file://src/ui/types/IGridTemplateParams.ts#L3-L20)
|
|||
|
|
|
|||
|
|
## ResizeObserver中的动态网格计算逻辑
|
|||
|
|
当容器尺寸发生变化时,`ResizeObserver`回调函数会触发重新计算流程。关键步骤如下:
|
|||
|
|
|
|||
|
|
1. **获取容器几何信息**:通过`getBoundingClientRect()`获取当前容器的实际宽高。
|
|||
|
|
2. **计算列数(colCount)**:
|
|||
|
|
```ts
|
|||
|
|
gridTemplate.colCount = Math.floor((containerRect.width + gridTemplate.gapX) / (gridTemplate.cellExpectWidth + gridTemplate.gapX));
|
|||
|
|
```
|
|||
|
|
3. **计算行数(rowCount)**:
|
|||
|
|
```ts
|
|||
|
|
gridTemplate.rowCount = Math.floor((containerRect.height + gridTemplate.gapY) / (gridTemplate.cellExpectHeight + gridTemplate.gapY));
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
此算法的本质是将容器总宽度(或高度)加上一个间隙值,再除以“单个单元格宽度+列间距”,从而避免因浮点误差导致最后一列无法完整显示的问题。使用`Math.floor`向下取整保证结果为有效整数。
|
|||
|
|
|
|||
|
|
**Section sources**
|
|||
|
|
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L39-L40)
|
|||
|
|
|
|||
|
|
## 实际单元格尺寸的精确控制
|
|||
|
|
在确定了行列数量后,系统进一步计算每个单元格的实际像素尺寸,以充分利用可用空间并消除边缘空白。
|
|||
|
|
|
|||
|
|
### 计算公式推导
|
|||
|
|
- **可用总宽度** = 容器宽度 - 所有列间隙之和
|
|||
|
|
即:`w = containerRect.width - gapX * (colCount - 1)`
|
|||
|
|
- **每列实际宽度** = 可用总宽度 ÷ 列数
|
|||
|
|
即:`cellRealWidth = w / colCount`
|
|||
|
|
|
|||
|
|
同理可得行方向上的计算:
|
|||
|
|
- `h = containerRect.height - gapY * (rowCount - 1)`
|
|||
|
|
- `cellRealHeight = h / rowCount`
|
|||
|
|
|
|||
|
|
### 浮点数精度控制
|
|||
|
|
由于浏览器渲染对小数像素的支持有限,直接使用浮点值可能导致布局抖动或错位。因此系统采用`toFixed(2)`保留两位小数,并通过`Number()`转换回数值类型,既保证精度又提升渲染稳定性。
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
gridTemplate.cellRealWidth = Number((w / gridTemplate.colCount).toFixed(2))
|
|||
|
|
gridTemplate.cellRealHeight = Number((h / gridTemplate.rowCount).toFixed(2))
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这种处理方式平衡了空间利用率与视觉平滑性。
|
|||
|
|
|
|||
|
|
**Section sources**
|
|||
|
|
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L41-L42)
|
|||
|
|
|
|||
|
|
## gridStyle样式对象的生成与绑定
|
|||
|
|
`gridStyle`是一个基于Vue `computed`的响应式计算属性,负责将`gridTemplate`中的参数转化为标准的CSS Grid样式规则。
|
|||
|
|
|
|||
|
|
### 样式对象结构
|
|||
|
|
```ts
|
|||
|
|
const gridStyle = computed(() => ({
|
|||
|
|
gridTemplateColumns: `repeat(${gridTemplate.colCount}, minmax(${gridTemplate.cellExpectWidth}px, 1fr))`,
|
|||
|
|
gridTemplateRows: `repeat(${gridTemplate.rowCount}, minmax(${gridTemplate.cellExpectHeight}px, 1fr))`,
|
|||
|
|
gap: `${gridTemplate.gapX}px ${gridTemplate.gapY}px`
|
|||
|
|
}))
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 关键特性说明
|
|||
|
|
- **`minmax()`函数应用**:确保每列最小宽度不低于`cellExpectWidth`,但允许在空间充足时扩展至等分的`1fr`比例。
|
|||
|
|
- **动态重复语法**:`repeat(colCount, ...)`自动构建指定数量的轨道定义。
|
|||
|
|
- **双向间隙设置**:`gap`属性分别设置横向与纵向间距。
|
|||
|
|
|
|||
|
|
该样式对象最终通过`:style="gridStyle"`绑定到`.desktop-icons-container`元素上,实现视图层的实时更新。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
A[容器尺寸变化] --> B{ResizeObserver触发}
|
|||
|
|
B --> C[计算colCount/rrowCount]
|
|||
|
|
C --> D[计算cellRealWidth/Height]
|
|||
|
|
D --> E[更新gridTemplate响应式对象]
|
|||
|
|
E --> F[gridStyle重新计算]
|
|||
|
|
F --> G[DOM样式自动更新]
|
|||
|
|
G --> H[完成布局重绘]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Diagram sources**
|
|||
|
|
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L20-L30)
|
|||
|
|
- [DesktopContainer.vue](file://src/ui/desktop-container/DesktopContainer.vue#L1)
|
|||
|
|
|
|||
|
|
**Section sources**
|
|||
|
|
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L20-L30)
|
|||
|
|
- [DesktopContainer.vue](file://src/ui/desktop-container/DesktopContainer.vue#L1)
|
|||
|
|
|
|||
|
|
## 图标重排机制分析
|
|||
|
|
每当行列数发生变更时,系统会调用`rearrangeIcons`函数对所有图标进行位置重分配,确保其不超出可视范围且无重叠。
|
|||
|
|
|
|||
|
|
### 重排策略
|
|||
|
|
1. **优先保留原有坐标**:若图标的原位置仍在新网格范围内且未被占用,则保留原位。
|
|||
|
|
2. **空位填充机制**:对于越界或冲突的图标,遍历网格寻找首个可用空位(从左上角开始)。
|
|||
|
|
3. **溢出图标管理**:当网格已满时,超出部分存入`hideAppIcons`数组,可用于后续提示用户。
|
|||
|
|
|
|||
|
|
该机制保障了用户体验的一致性,避免图标因窗口缩放而丢失或错乱。
|
|||
|
|
|
|||
|
|
**Section sources**
|
|||
|
|
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L102-L156)
|
|||
|
|
|
|||
|
|
## 总结
|
|||
|
|
本系统的动态网格计算机制充分体现了响应式设计的思想。通过结合`ResizeObserver`、Vue响应式系统与CSS Grid布局,实现了从容器尺寸→行列数量→单元格尺寸→样式绑定→图标定位的完整闭环。特别是在实际尺寸计算中对间隙总和的扣除与浮点精度的控制,展现了对细节的高度关注。整体架构清晰、逻辑严谨,具备良好的可维护性与扩展性。
|