Files
yinjianm 26acdba7e8 fix(frontend): 修复文件管理器右键子菜单关闭竞态
移除文件管理器右键菜单在捕获阶段注册的全局点击关闭监听
将关闭职责统一收敛到组件层 click-outside 处理

避免终端、上传、压缩等子菜单在展开或点击前被提前关闭
同时同步更新相关知识库记录与中英文 README 链接
2026-03-26 05:56:00 +08:00

73 lines
3.9 KiB
Markdown

# 变更提案: file-manager-context-submenu-regression
## 元信息
```yaml
类型: 修复
方案类型: implementation
优先级: P1
状态: 已完成
状态说明: 已移除右键菜单的捕获阶段全局关闭监听,恢复终端、上传、压缩等子菜单的展开与点击
创建: 2026-03-26
```
---
## 1. 需求
### 背景
文件管理器右键菜单近期已经重排并补齐了终端、上传、压缩等二级菜单能力,但当前实际页面中点击这些带子菜单的项没有任何反应,副菜单无法展开,用户无法从右键菜单执行相关动作。
### 目标
- 修复文件管理器右键菜单的子菜单展开与点击交互。
- 保持普通菜单项、空白处右键、多选右键和已有“发送到”行为继续可用。
- 将改动范围限制在右键菜单链路,不扩散到上传、压缩或终端业务逻辑本身。
### 约束条件
```yaml
范围约束: 优先限制在 FileManagerContextMenu.vue 与 useFileManagerContextMenu.ts
行为约束: 不改变现有菜单结构、文案顺序和菜单项语义
兼容约束: 桌面端 hover/click 展开子菜单,移动端平铺子菜单逻辑保持不变
验证约束: 至少完成前端静态构建验证;若无浏览器现场,明确标注手工回归项
```
### 验收标准
- [x] 右键单文件或目录时,点击“终端 / 上传 / 压缩”可稳定展开对应副菜单。
- [x] 副菜单项可点击并触发既有 action,而不会在点击前被全局关闭监听提前销毁。
- [x] 普通菜单项仍可点击关闭菜单,不引入空白处无法关闭或菜单残留的问题。
- [x] 前端构建通过。
---
## 2. 方案
### 技术方案
根因集中在右键菜单的关闭时序。当前菜单打开后会在 `useFileManagerContextMenu.ts` 中注册 `document.addEventListener('click', hideContextMenu, { capture: true, once: true })`,这会在捕获阶段先于菜单项自身的 `@click.stop` 执行,导致带子菜单的项在展开或点击前就被整体关闭。修复路径是把关闭逻辑收敛到组件内的 click-outside 处理,移除 composable 中的捕获式一次性关闭监听,保留菜单组件对外发出的 `close-request` 作为唯一关闭入口。这样菜单内部点击、子菜单 hover/click 和菜单外点击的边界会更稳定,也不会改变已有 action 回调。
### 影响范围
```yaml
涉及模块:
- frontend: FileManagerContextMenu.vue
- frontend: useFileManagerContextMenu.ts
预计变更文件: 2-4
```
### 风险评估
| 风险 | 等级 | 应对 |
|------|------|------|
| 移除全局关闭监听后,菜单可能出现点击外部不关闭 | 中 | 复用组件内既有 `handleClickOutside`,并验证 `close-request` 路径 |
| 子菜单延时关闭逻辑与普通点击关闭冲突 | 低 | 保持 `expandedSubmenu` 的现有策略,仅修正外层竞态 |
| 菜单位置计算依赖渲染时机,删除监听后可能遗漏现有定位行为 | 低 | 不修改定位逻辑,只去掉与关闭相关的捕获监听 |
### 决策
### file-manager-context-submenu-regression#D001: 右键菜单关闭职责统一收敛到组件层
**背景**: 子菜单无法展开的根因不是业务 action 缺失,而是外层 composable 在捕获阶段过早关闭菜单。
**备选**:
| 方案 | 优点 | 缺点 |
|------|------|------|
| A. 只调整子菜单项的点击事件 | 改动看似更小 | 无法解决捕获阶段先触发的问题,症状容易反复 |
| B. 移除 composable 的捕获式全局关闭监听,统一由组件层处理点击外部关闭 | 直接消除竞态,职责清晰 | 需要确认组件层外部点击关闭覆盖完整 |
**选择**: 方案 B。
**理由**: 根因在关闭时序,不在菜单项自身;统一到组件层能最小化改动同时保证内部点击不再被抢先吞掉。
**影响**: 仅影响文件管理器右键菜单关闭链路,不改动终端/上传/压缩业务实现。