20260823210241
This commit is contained in:
1 parent
5ff4583aeb
commit
f4c7413dc6
2766 files changed
+1836409
-94689
No files matched your search
@@ -0,0 +1,497 @@
|
||||
# 组件工具集
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [drag.js](file://fms-vue/src/components/ui/utils/drag.js)
|
||||
- [focus.js](file://fms-vue/src/components/ui/utils/focus.js)
|
||||
- [position.js](file://fms-vue/src/components/ui/utils/position.js)
|
||||
- [scroll.js](file://fms-vue/src/components/ui/utils/scroll.js)
|
||||
- [useHotkeys.js](file://fms-vue/src/composables/useHotkeys.js)
|
||||
- [tree.js](file://fms-vue/src/utils/tree.js)
|
||||
- [dataChanges.js](file://fms-vue/src/utils/dataChanges.js)
|
||||
- [utils.spec.js](file://fms-vue/tests/unit/utils.spec.js)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向 FMS 前端组件库中的通用工具集,聚焦以下能力:拖拽与缩放、焦点管理、浮层定位、滚动锁定、快捷键注册、树形数据构建与排序、表格变更计算等。文档旨在帮助开发者理解各工具函数的设计理念、API 接口、参数配置与返回值处理,并给出在组件开发中的复用模式、最佳实践、测试用例与性能基准建议,以及扩展机制与自定义实现方案。
|
||||
|
||||
## 项目结构
|
||||
工具集主要分布在以下路径:
|
||||
- UI 工具:位于 fms-vue/src/components/ui/utils,包含 drag.js、focus.js、position.js、scroll.js
|
||||
- 组合式函数:位于 fms-vue/src/composables,包含 useHotkeys.js
|
||||
- 通用工具:位于 fms-vue/src/utils,包含 tree.js、dataChanges.js
|
||||
- 单元测试:位于 fms-vue/tests/unit,包含 utils.spec.js(覆盖 tree 工具)
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "UI 工具"
|
||||
D["drag.js"]
|
||||
F["focus.js"]
|
||||
P["position.js"]
|
||||
S["scroll.js"]
|
||||
end
|
||||
subgraph "组合式函数"
|
||||
H["useHotkeys.js"]
|
||||
end
|
||||
subgraph "通用工具"
|
||||
T["tree.js"]
|
||||
C["dataChanges.js"]
|
||||
end
|
||||
subgraph "测试"
|
||||
U["utils.spec.js"]
|
||||
end
|
||||
U --> T
|
||||
H --> |键盘事件| D
|
||||
D --> |弹窗交互| F
|
||||
D --> |弹窗定位| P
|
||||
D --> |弹窗滚动| S
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [drag.js:1-202](file://fms-vue/src/components/ui/utils/drag.js#L1-L202)
|
||||
- [focus.js:1-63](file://fms-vue/src/components/ui/utils/focus.js#L1-L63)
|
||||
- [position.js:1-99](file://fms-vue/src/components/ui/utils/position.js#L1-L99)
|
||||
- [scroll.js:1-42](file://fms-vue/src/components/ui/utils/scroll.js#L1-L42)
|
||||
- [useHotkeys.js:1-57](file://fms-vue/src/composables/useHotkeys.js#L1-L57)
|
||||
- [tree.js:1-56](file://fms-vue/src/utils/tree.js#L1-L56)
|
||||
- [dataChanges.js:1-58](file://fms-vue/src/utils/dataChanges.js#L1-L58)
|
||||
- [utils.spec.js:1-120](file://fms-vue/tests/unit/utils.spec.js#L1-L120)
|
||||
|
||||
章节来源
|
||||
- [drag.js:1-202](file://fms-vue/src/components/ui/utils/drag.js#L1-L202)
|
||||
- [focus.js:1-63](file://fms-vue/src/components/ui/utils/focus.js#L1-L63)
|
||||
- [position.js:1-99](file://fms-vue/src/components/ui/utils/position.js#L1-L99)
|
||||
- [scroll.js:1-42](file://fms-vue/src/components/ui/utils/scroll.js#L1-L42)
|
||||
- [useHotkeys.js:1-57](file://fms-vue/src/composables/useHotkeys.js#L1-L57)
|
||||
- [tree.js:1-56](file://fms-vue/src/utils/tree.js#L1-L56)
|
||||
- [dataChanges.js:1-58](file://fms-vue/src/utils/dataChanges.js#L1-L58)
|
||||
- [utils.spec.js:1-120](file://fms-vue/tests/unit/utils.spec.js#L1-L120)
|
||||
|
||||
## 核心组件
|
||||
本节概述各工具的职责边界与协作方式:
|
||||
- 拖拽与缩放(drag.js):提供面板移动与尺寸缩放的纯 DOM 辅助,基于 Pointer Events,支持约束、最小/最大尺寸、回调通知。
|
||||
- 焦点管理(focus.js):为 Modal/Drawer 等对话框提供可聚焦元素获取、首项聚焦、Tab 焦点陷阱。
|
||||
- 位置计算(position.js):根据触发器与期望方位计算无碰撞的浮层坐标,支持翻转与视口裁剪。
|
||||
- 滚动控制(scroll.js):多弹窗共享的 body 滚动锁定/解锁,避免内容跳动。
|
||||
- 快捷键(useHotkeys.js):全局键盘快捷键注册,支持修饰键精确匹配、输入态忽略策略。
|
||||
- 树工具(tree.js):一维数组构建树、递归排序。
|
||||
- 数据变更(dataChanges.js):行级差异计算、临时 ID 分配、外键重映射、变更封装与存在性判断。
|
||||
|
||||
章节来源
|
||||
- [drag.js:1-202](file://fms-vue/src/components/ui/utils/drag.js#L1-L202)
|
||||
- [focus.js:1-63](file://fms-vue/src/components/ui/utils/focus.js#L1-L63)
|
||||
- [position.js:1-99](file://fms-vue/src/components/ui/utils/position.js#L1-L99)
|
||||
- [scroll.js:1-42](file://fms-vue/src/components/ui/utils/scroll.js#L1-L42)
|
||||
- [useHotkeys.js:1-57](file://fms-vue/src/composables/useHotkeys.js#L1-L57)
|
||||
- [tree.js:1-56](file://fms-vue/src/utils/tree.js#L1-L56)
|
||||
- [dataChanges.js:1-58](file://fms-vue/src/utils/dataChanges.js#L1-L58)
|
||||
|
||||
## 架构总览
|
||||
工具集以“纯函数 + 轻量副作用”的方式组织:
|
||||
- 纯函数:computePosition、buildTree、sortTree、diffRows 等,便于单测与替换。
|
||||
- 轻量副作用:drag/resize 监听绑定、body 滚动样式修改、焦点捕获等,均提供 destroy/reset 或成对 API。
|
||||
- 组合式函数:useHotkeys 将生命周期与事件绑定封装,供 Vue 组件直接调用。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "组件"
|
||||
participant HK as "useHotkeys"
|
||||
participant DR as "drag(拖拽)"
|
||||
participant PO as "position(定位)"
|
||||
participant SC as "scroll(滚动锁)"
|
||||
participant FO as "focus(焦点)"
|
||||
C->>HK : 注册快捷键
|
||||
C->>DR : bindDrag/bindResize
|
||||
C->>PO : computePosition(触发器/期望方位/偏移/视口)
|
||||
C->>SC : lockScroll()
|
||||
C->>FO : focusFirst/trapFocus
|
||||
Note over C,FO : 弹窗打开时:锁定滚动、聚焦容器、计算落点、启用拖拽
|
||||
C-->>SC : unlockScroll()
|
||||
C-->>DR : destroy()
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [useHotkeys.js:22-57](file://fms-vue/src/composables/useHotkeys.js#L22-L57)
|
||||
- [drag.js:26-111](file://fms-vue/src/components/ui/utils/drag.js#L26-L111)
|
||||
- [position.js:76-99](file://fms-vue/src/components/ui/utils/position.js#L76-L99)
|
||||
- [scroll.js:15-42](file://fms-vue/src/components/ui/utils/scroll.js#L15-L42)
|
||||
- [focus.js:22-63](file://fms-vue/src/components/ui/utils/focus.js#L22-L63)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 拖拽与缩放(drag.js)
|
||||
- 设计要点
|
||||
- 基于 Pointer Events,统一鼠标与触屏行为。
|
||||
- 通过 transform 与 inline 尺寸更新,不改变文档流布局。
|
||||
- 提供 reset/destroy 方法,确保资源释放与状态复位。
|
||||
- 关键 API
|
||||
- bindDrag(panel, handle, options)
|
||||
- 参数:panel(被移动面板)、handle(拖拽手柄)、options.constrain(是否约束视口)、options.minVisible(至少保留像素数)
|
||||
- 返回:{ reset(), destroy() }
|
||||
- bindResize(panel, handle, options)
|
||||
- 参数:direction(方向 e/w/s/n 组合)、minWidth/minHeight/maxWidth/maxHeight、onResize(size)
|
||||
- 返回:{ destroy() }
|
||||
- 使用建议
|
||||
- 在组件挂载时绑定,卸载前调用 destroy。
|
||||
- 结合 position.js 计算初始落点,结合 scroll.js 锁定滚动。
|
||||
- 在 handle 内屏蔽按钮/链接/表单控件的拖拽触发。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["指针按下"]) --> CheckTarget{"目标是否为可拖拽区域?"}
|
||||
CheckTarget --> |否| End(["结束"])
|
||||
CheckTarget --> |是| Capture["捕获指针/记录起点"]
|
||||
Capture --> Move{"指针移动"}
|
||||
Move --> Calc["计算新位置/尺寸<br/>应用约束/回调 onResize"]
|
||||
Calc --> Apply["设置 transform/inline 尺寸"]
|
||||
Apply --> Move
|
||||
Move --> |抬起/取消| Release["释放指针/恢复 userSelect"]
|
||||
Release --> End
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [drag.js:43-111](file://fms-vue/src/components/ui/utils/drag.js#L43-L111)
|
||||
- [drag.js:147-200](file://fms-vue/src/components/ui/utils/drag.js#L147-L200)
|
||||
|
||||
章节来源
|
||||
- [drag.js:1-202](file://fms-vue/src/components/ui/utils/drag.js#L1-L202)
|
||||
|
||||
### 焦点管理(focus.js)
|
||||
- 设计要点
|
||||
- 仅操作 DOM,不读取组件状态;提供可聚焦元素筛选、首项聚焦、Tab 循环陷阱。
|
||||
- 过滤不可见元素(getClientRects),避免隐藏元素干扰。
|
||||
- 关键 API
|
||||
- getFocusable(container):返回可见且可聚焦的元素数组
|
||||
- focusFirst(container):聚焦第一个可聚焦元素,否则聚焦容器
|
||||
- trapFocus(event, container):在容器 keydown 上调用,实现 Tab 循环
|
||||
- 使用建议
|
||||
- 弹窗打开后调用 focusFirst 聚焦容器内部首个可聚焦元素。
|
||||
- 在容器 keydown 事件中调用 trapFocus,保证键盘可达性。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["容器 keydown (Tab)"] --> B{"是否有可聚焦元素?"}
|
||||
B --> |否| C["阻止默认并聚焦容器"]
|
||||
B --> |是| D{"Shift+Tab 且当前为首项/容器外?"}
|
||||
D --> |是| E["阻止默认并聚焦末项"]
|
||||
D --> |否| F{"Tab 且当前为末项/容器外?"}
|
||||
F --> |是| G["阻止默认并聚焦首项"]
|
||||
F --> |否| H["保持当前焦点"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [focus.js:22-63](file://fms-vue/src/components/ui/utils/focus.js#L22-L63)
|
||||
|
||||
章节来源
|
||||
- [focus.js:1-63](file://fms-vue/src/components/ui/utils/focus.js#L1-L63)
|
||||
|
||||
### 位置计算(position.js)
|
||||
- 设计要点
|
||||
- 纯函数 computePosition,输入触发器矩形、浮层尺寸、期望方位、偏移与视口,输出无碰撞坐标与实际方位。
|
||||
- 支持主方向翻转(flip)与视口裁剪(shift)。
|
||||
- 关键 API
|
||||
- computePosition({ placement, triggerRect, floatSize, offset, viewport })
|
||||
- 返回:{ x, y, placement }
|
||||
- 使用建议
|
||||
- 在弹窗显示前计算落点,结合 transform translate 定位。
|
||||
- 窗口大小变化时重新计算。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S["开始"] --> P["解析 placement(base, alignment)"]
|
||||
P --> Place["按 base+alignment 计算初始坐标"]
|
||||
Place --> Over{"是否溢出视口?"}
|
||||
Over --> |是| Flip["尝试相反方向"]
|
||||
Flip --> CheckFlip{"翻转后是否仍溢出?"}
|
||||
CheckFlip --> |是| Keep["保持原方向"]
|
||||
CheckFlip --> |否| UseFlip["采用翻转方向"]
|
||||
Over --> |否| Keep
|
||||
UseFlip --> Clamp["约束到视口内"]
|
||||
Keep --> Clamp
|
||||
Clamp --> R["返回 {x,y,placement}"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [position.js:29-99](file://fms-vue/src/components/ui/utils/position.js#L29-L99)
|
||||
|
||||
章节来源
|
||||
- [position.js:1-99](file://fms-vue/src/components/ui/utils/position.js#L1-L99)
|
||||
|
||||
### 滚动控制(scroll.js)
|
||||
- 设计要点
|
||||
- 模块级引用计数,支持多个弹窗同时打开;首次锁定记录原始样式并补偿滚动条宽度,避免内容横向跳动。
|
||||
- 关键 API
|
||||
- lockScroll():锁定 body 滚动
|
||||
- unlockScroll():解锁 body 滚动
|
||||
- 使用建议
|
||||
- 弹窗打开时 lockScroll,关闭时 unlockScroll;确保成对调用。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 空闲
|
||||
空闲 --> 已锁定 : "lockScroll()"
|
||||
已锁定 --> 已解锁 : "unlockScroll() 且计数归零"
|
||||
已锁定 --> 已锁定 : "多次 lockScroll()"
|
||||
已解锁 --> 已锁定 : "再次 lockScroll()"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [scroll.js:8-42](file://fms-vue/src/components/ui/utils/scroll.js#L8-L42)
|
||||
|
||||
章节来源
|
||||
- [scroll.js:1-42](file://fms-vue/src/components/ui/utils/scroll.js#L1-L42)
|
||||
|
||||
### 快捷键(useHotkeys.js)
|
||||
- 设计要点
|
||||
- 全局键盘事件监听,支持修饰键精确匹配(mod/ctrl/meta/alt/shift)。
|
||||
- 可选 ignoreWhenTyping,在输入态下忽略非保存类快捷键。
|
||||
- 自动在 onMounted/onBeforeUnmount 中注册/解绑。
|
||||
- 关键 API
|
||||
- useHotkeys(shortcuts):接收快捷键数组,每项含 key、修饰符、ignoreWhenTyping、handler
|
||||
- 使用建议
|
||||
- 在组件顶层调用,传入业务 handler;保存类快捷键设置 ignoreWhenTyping=false。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as "用户按键"
|
||||
participant W as "window"
|
||||
participant HK as "useHotkeys"
|
||||
U->>W : keydown
|
||||
W->>HK : 分发事件
|
||||
HK->>HK : matches(e, s) 校验修饰键
|
||||
HK->>HK : ignoreWhenTyping? 输入态判断
|
||||
HK->>HK : preventDefault()
|
||||
HK-->>U : 执行 handler
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [useHotkeys.js:4-57](file://fms-vue/src/composables/useHotkeys.js#L4-L57)
|
||||
|
||||
章节来源
|
||||
- [useHotkeys.js:1-57](file://fms-vue/src/composables/useHotkeys.js#L1-L57)
|
||||
|
||||
### 树工具(tree.js)
|
||||
- 设计要点
|
||||
- buildTree:将一维列表按 parentKey 构建树,支持自定义 idKey/parentKey/childrenKey。
|
||||
- sortTree:按 b_xh 升序、b_id 兜底进行递归排序。
|
||||
- 关键 API
|
||||
- buildTree(list, idKey, parentKey, childrenKey)
|
||||
- sortTree(tree, xhKey, idKey)
|
||||
- 注意事项
|
||||
- 当前实现会向父节点注入 children 属性(副作用),若需纯函数可在上层做深拷贝。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["输入一维列表"] --> B["建立 id->节点 映射"]
|
||||
B --> C{"遍历节点"}
|
||||
C --> |有父节点且存在| D["加入父节点 children"]
|
||||
C --> |无父节点| E["加入根数组"]
|
||||
D --> F["返回根数组"]
|
||||
E --> F
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [tree.js:8-35](file://fms-vue/src/utils/tree.js#L8-L35)
|
||||
|
||||
章节来源
|
||||
- [tree.js:1-56](file://fms-vue/src/utils/tree.js#L1-L56)
|
||||
|
||||
### 数据变更(dataChanges.js)
|
||||
- 设计要点
|
||||
- diffRows:基于 b_id 对比前后数据,返回 inserts/updates/deletes。
|
||||
- allocateTemporaryIds:批量分配临时 ID,并将负数临时 ID 映射为真实 ID。
|
||||
- remapForeignKeys:将外键字段值按映射表替换为新 ID。
|
||||
- tableChange:封装表格变更请求体。
|
||||
- hasChanges:判断是否存在变更。
|
||||
- 关键 API
|
||||
- cloneData(value)
|
||||
- diffRows(current, previous)
|
||||
- allocateTemporaryIds(rowGroups)
|
||||
- remapForeignKeys(rows, fields, mapping)
|
||||
- tableChange(table, changes)
|
||||
- hasChanges(request)
|
||||
- 使用建议
|
||||
- 在提交前调用 diffRows 生成变更集,必要时调用 allocateTemporaryIds 与 remapForeignKeys 完成 ID 对齐。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S["开始"] --> D["diffRows(current, previous)"]
|
||||
D --> I{"是否存在插入/更新/删除?"}
|
||||
I --> |是| T["tableChange(table, changes)"]
|
||||
I --> |否| E["结束"]
|
||||
T --> M{"是否需要临时ID映射?"}
|
||||
M --> |是| A["allocateTemporaryIds(rowGroups)"]
|
||||
A --> R["remapForeignKeys(rows, fields, mapping)"]
|
||||
R --> E
|
||||
M --> |否| E
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [dataChanges.js:7-58](file://fms-vue/src/utils/dataChanges.js#L7-L58)
|
||||
|
||||
章节来源
|
||||
- [dataChanges.js:1-58](file://fms-vue/src/utils/dataChanges.js#L1-L58)
|
||||
|
||||
## 依赖关系分析
|
||||
- 低耦合:各工具以独立模块暴露 API,组件按需引入。
|
||||
- 协作点:
|
||||
- 弹窗场景:scroll.lockScroll → focus.focusFirst → position.computePosition → drag.bindDrag/bindResize
|
||||
- 快捷键场景:useHotkeys 触发业务逻辑,可能间接调用上述工具。
|
||||
- 外部依赖:
|
||||
- 浏览器 API:Pointer Events、DOMRect、getBoundingClientRect、document.body.style
|
||||
- 服务接口:dataChanges 依赖 nextIdApi 用于临时 ID 分配
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
HK["useHotkeys"] --> |触发| UI["弹窗/表单"]
|
||||
UI --> SC["scroll.lock/unlock"]
|
||||
UI --> FO["focus.focusFirst/trapFocus"]
|
||||
UI --> PO["position.computePosition"]
|
||||
UI --> DR["drag.bindDrag/bindResize"]
|
||||
DC["dataChanges"] --> API["nextIdApi"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [useHotkeys.js:22-57](file://fms-vue/src/composables/useHotkeys.js#L22-L57)
|
||||
- [scroll.js:15-42](file://fms-vue/src/components/ui/utils/scroll.js#L15-L42)
|
||||
- [focus.js:22-63](file://fms-vue/src/components/ui/utils/focus.js#L22-L63)
|
||||
- [position.js:76-99](file://fms-vue/src/components/ui/utils/position.js#L76-L99)
|
||||
- [drag.js:26-200](file://fms-vue/src/components/ui/utils/drag.js#L26-L200)
|
||||
- [dataChanges.js:22-40](file://fms-vue/src/utils/dataChanges.js#L22-L40)
|
||||
|
||||
章节来源
|
||||
- [useHotkeys.js:1-57](file://fms-vue/src/composables/useHotkeys.js#L1-L57)
|
||||
- [scroll.js:1-42](file://fms-vue/src/components/ui/utils/scroll.js#L1-L42)
|
||||
- [focus.js:1-63](file://fms-vue/src/components/ui/utils/focus.js#L1-L63)
|
||||
- [position.js:1-99](file://fms-vue/src/components/ui/utils/position.js#L1-L99)
|
||||
- [drag.js:1-202](file://fms-vue/src/components/ui/utils/drag.js#L1-L202)
|
||||
- [dataChanges.js:1-58](file://fms-vue/src/utils/dataChanges.js#L1-L58)
|
||||
|
||||
## 性能考量
|
||||
- 事件监听与内存
|
||||
- drag/resize 必须调用 destroy 解绑事件,避免内存泄漏。
|
||||
- useHotkeys 在组件卸载时自动解绑,无需手动管理。
|
||||
- 渲染与布局
|
||||
- 拖拽使用 transform 与 inline 尺寸,减少回流;避免频繁读取布局属性。
|
||||
- 定位 computePosition 为纯函数,建议在尺寸/位置变化时缓存结果,仅在必要时重算。
|
||||
- 大数据处理
|
||||
- diffRows 使用 Map 加速查找,时间复杂度近似 O(n)。
|
||||
- buildTree 两遍扫描,时间复杂度 O(n),注意 children 注入的副作用。
|
||||
- 滚动锁定
|
||||
- 使用引用计数避免重复设置样式;首次锁定补偿滚动条宽度,防止抖动。
|
||||
|
||||
[本节为通用指导,不直接分析具体文件]
|
||||
|
||||
## 故障排查指南
|
||||
- 拖拽异常
|
||||
- 现象:拖拽无效或越界
|
||||
- 排查:确认传入 panel/handle 有效;检查 constrain/minVisible 配置;确保未点击到屏蔽元素(button/a/input 等)
|
||||
- 参考:[drag.js:43-79](file://fms-vue/src/components/ui/utils/drag.js#L43-L79)
|
||||
- 焦点丢失
|
||||
- 现象:弹窗打开后无法用 Tab 切换
|
||||
- 排查:确认容器 keydown 调用 trapFocus;确认 getFocusable 能拿到可见元素
|
||||
- 参考:[focus.js:22-63](file://fms-vue/src/components/ui/utils/focus.js#L22-L63)
|
||||
- 浮层溢出
|
||||
- 现象:浮层被遮挡或超出视口
|
||||
- 排查:检查 placement、offset、viewport 尺寸;确认 computePosition 返回值并正确应用
|
||||
- 参考:[position.js:76-99](file://fms-vue/src/components/ui/utils/position.js#L76-L99)
|
||||
- 页面滚动异常
|
||||
- 现象:弹窗打开后页面仍可滚动或出现跳动
|
||||
- 排查:确保 lockScroll/unlockScroll 成对调用;检查引用计数是否正确
|
||||
- 参考:[scroll.js:15-42](file://fms-vue/src/components/ui/utils/scroll.js#L15-L42)
|
||||
- 快捷键冲突
|
||||
- 现象:快捷键未触发或被浏览器默认行为拦截
|
||||
- 排查:检查 ignoreWhenTyping;确认 handler 中 preventDefault;核对修饰键匹配规则
|
||||
- 参考:[useHotkeys.js:4-57](file://fms-vue/src/composables/useHotkeys.js#L4-L57)
|
||||
|
||||
章节来源
|
||||
- [drag.js:43-111](file://fms-vue/src/components/ui/utils/drag.js#L43-L111)
|
||||
- [focus.js:22-63](file://fms-vue/src/components/ui/utils/focus.js#L22-L63)
|
||||
- [position.js:76-99](file://fms-vue/src/components/ui/utils/position.js#L76-L99)
|
||||
- [scroll.js:15-42](file://fms-vue/src/components/ui/utils/scroll.js#L15-L42)
|
||||
- [useHotkeys.js:4-57](file://fms-vue/src/composables/useHotkeys.js#L4-L57)
|
||||
|
||||
## 结论
|
||||
本工具集围绕“可复用、可测试、可扩展”的原则,提供了弹窗与交互场景中常用的基础能力。通过纯函数与轻量副作用的组合,既保证了稳定性与可维护性,又便于在不同组件中灵活拼装。建议在实际项目中:
|
||||
- 以弹窗为中心串联 scroll/focus/position/drag,形成一致的交互体验。
|
||||
- 使用 useHotkeys 统一管理快捷键,提升可访问性与一致性。
|
||||
- 借助 tree/dataChanges 工具简化复杂数据结构的处理。
|
||||
- 完善测试覆盖,关注性能回归与边界条件。
|
||||
|
||||
[本节为总结性内容,不直接分析具体文件]
|
||||
|
||||
## 附录
|
||||
|
||||
### API 速查表
|
||||
- 拖拽与缩放
|
||||
- bindDrag(panel, handle, options): 返回 { reset, destroy }
|
||||
- bindResize(panel, handle, options): 返回 { destroy }
|
||||
- 焦点管理
|
||||
- getFocusable(container): HTMLElement[]
|
||||
- focusFirst(container): void
|
||||
- trapFocus(event, container): void
|
||||
- 位置计算
|
||||
- computePosition({ placement, triggerRect, floatSize, offset, viewport }): { x, y, placement }
|
||||
- 滚动控制
|
||||
- lockScroll(): void
|
||||
- unlockScroll(): void
|
||||
- 快捷键
|
||||
- useHotkeys(shortcuts): void
|
||||
- 树工具
|
||||
- buildTree(list, idKey, parentKey, childrenKey): Array
|
||||
- sortTree(tree, xhKey, idKey): Array
|
||||
- 数据变更
|
||||
- cloneData(value): any
|
||||
- diffRows(current, previous): { inserts, updates, deletes }
|
||||
- allocateTemporaryIds(rowGroups): Promise<Map>
|
||||
- remapForeignKeys(rows, fields, mapping): void
|
||||
- tableChange(table, changes): Object
|
||||
- hasChanges(request): boolean
|
||||
|
||||
章节来源
|
||||
- [drag.js:26-200](file://fms-vue/src/components/ui/utils/drag.js#L26-L200)
|
||||
- [focus.js:22-63](file://fms-vue/src/components/ui/utils/focus.js#L22-L63)
|
||||
- [position.js:76-99](file://fms-vue/src/components/ui/utils/position.js#L76-L99)
|
||||
- [scroll.js:15-42](file://fms-vue/src/components/ui/utils/scroll.js#L15-L42)
|
||||
- [useHotkeys.js:22-57](file://fms-vue/src/composables/useHotkeys.js#L22-L57)
|
||||
- [tree.js:8-56](file://fms-vue/src/utils/tree.js#L8-L56)
|
||||
- [dataChanges.js:3-58](file://fms-vue/src/utils/dataChanges.js#L3-L58)
|
||||
|
||||
### 测试用例与基准
|
||||
- 现有用例
|
||||
- 树工具:空数组、父子关系、孤儿节点、自定义键名、副作用说明、排序与递归排序、返回引用等
|
||||
- 主题工具:主色变量写入、暗色模式 class 切换
|
||||
- 建议补充
|
||||
- 拖拽:约束边界、最小/最大尺寸、reset/destroy 行为
|
||||
- 焦点:无焦点元素时的回退、Shift+Tab 与 Tab 循环
|
||||
- 定位:翻转与 shift 行为、极端视口尺寸
|
||||
- 滚动:多次 lock/unlock 的引用计数
|
||||
- 快捷键:修饰键组合、输入态忽略、preventDefault
|
||||
- 性能基准建议
|
||||
- 使用浏览器 Performance API 或专用测量脚本,统计关键路径耗时(如 computePosition、diffRows、buildTree)
|
||||
- 针对大数据量场景(rows > 10k)评估 diffRows 与 buildTree 的耗时与内存占用
|
||||
- 在高频拖拽场景下,验证 transform 更新频率与帧率
|
||||
|
||||
章节来源
|
||||
- [utils.spec.js:1-120](file://fms-vue/tests/unit/utils.spec.js#L1-L120)
|
||||
|
||||
### 扩展与自定义实现
|
||||
- 替换定位库:只需替换 position.js 的 computePosition 实现,保持输入输出一致即可。
|
||||
- 自定义拖拽行为:在 drag.js 的 onPointerMove 中扩展约束逻辑或增加吸附效果。
|
||||
- 扩展焦点策略:在 focus.js 中调整可聚焦选择器或添加无障碍增强。
|
||||
- 扩展快捷键:在 useHotkeys.js 中增加更多修饰符语义或上下文感知(如路由守卫)。
|
||||
- 扩展数据变更:在 dataChanges.js 中增加字段级 diff 或增量合并策略。
|
||||
|
||||
[本节为概念性指导,不直接分析具体文件]
|
||||
Reference in new issue
Block a user