fix(frontend): 修复文件管理器右键子菜单关闭竞态

移除文件管理器右键菜单在捕获阶段注册的全局点击关闭监听
将关闭职责统一收敛到组件层 click-outside 处理

避免终端、上传、压缩等子菜单在展开或点击前被提前关闭
同时同步更新相关知识库记录与中英文 README 链接
This commit is contained in:
yinjianm
2026-03-26 05:56:00 +08:00
parent cda7e0a018
commit 26acdba7e8
10 changed files with 144 additions and 35 deletions
+5
View File
@@ -8,6 +8,8 @@
- 2026-03-25:继续微调 `/workspace` Workbench,新增默认“快捷指令”标签、调整三栏宽度到更接近 xterminal 参考图,并修复终端区域鼠标悬停时指针异常消失的问题。 - 2026-03-25:继续微调 `/workspace` Workbench,新增默认“快捷指令”标签、调整三栏宽度到更接近 xterminal 参考图,并修复终端区域鼠标悬停时指针异常消失的问题。
### 修复 ### 修复
- **[frontend]**: 修复文件管理器右键菜单的回归关闭竞态,避免“终端 / 上传 / 压缩”子菜单在展开或点击前被捕获阶段监听提前关闭 — by yinjianm
- 方案: [202603260527_file-manager-context-submenu-regression](archive/2026-03/202603260527_file-manager-context-submenu-regression/)
- **[frontend]**: 修复文件管理器右键子菜单点击无反应、拖拽上传目标不明确,以及目录删除后持续报 `No such file` 的稳定性问题 — by yinjianm - **[frontend]**: 修复文件管理器右键子菜单点击无反应、拖拽上传目标不明确,以及目录删除后持续报 `No such file` 的稳定性问题 — by yinjianm
- 方案: [202603260324_file-manager-delete-upload-stability](archive/2026-03/202603260324_file-manager-delete-upload-stability/) - 方案: [202603260324_file-manager-delete-upload-stability](archive/2026-03/202603260324_file-manager-delete-upload-stability/)
- **[backend]**: 为 `sftp:rmdir` 增加 `recursive` 分支,让“仅删空目录”和“强制递归删除”分别落到 SFTP 原生删除与 `rm -rf` 链路 — by yinjianm - **[backend]**: 为 `sftp:rmdir` 增加 `recursive` 分支,让“仅删空目录”和“强制递归删除”分别落到 SFTP 原生删除与 `rm -rf` 链路 — by yinjianm
@@ -32,6 +34,9 @@
- 方案: [202603250614_terminal-ansi-color-effects](archive/2026-03/202603250614_terminal-ansi-color-effects/) - 方案: [202603250614_terminal-ansi-color-effects](archive/2026-03/202603250614_terminal-ansi-color-effects/)
### 快速修改 ### 快速修改
- **[workspace-root]**: 将双语 README 的仓库、发布与下载链接统一切到 `Micah123321/nexus-terminal`,移除 Ko-fi,并补充源项目指向 — by yinjianm
- 类型: 快速修改(无方案包)
- 文件: README.md, doc/README_EN.md
- **[frontend]**: 将前端关于页、版本检查和样式仓库默认链接切换到 `Micah123321/nexus-terminal`,并移除 Ko-fi 入口 — by yinjianm - **[frontend]**: 将前端关于页、版本检查和样式仓库默认链接切换到 `Micah123321/nexus-terminal`,并移除 Ko-fi 入口 — by yinjianm
- 类型: 快速修改(无方案包) - 类型: 快速修改(无方案包)
- 文件: packages/frontend/src/composables/settings/useVersionCheck.ts, packages/frontend/src/composables/settings/useAboutSection.ts, packages/frontend/src/components/settings/AboutSection.vue, packages/frontend/src/App.vue, packages/frontend/src/components/style-customizer/StyleCustomizerBackgroundTab.vue, package.json - 文件: packages/frontend/src/composables/settings/useVersionCheck.ts, packages/frontend/src/composables/settings/useAboutSection.ts, packages/frontend/src/components/settings/AboutSection.vue, packages/frontend/src/App.vue, packages/frontend/src/components/style-customizer/StyleCustomizerBackgroundTab.vue, package.json
+2 -2
View File
@@ -31,9 +31,9 @@
```yaml ```yaml
kb_version: 2.3.7 kb_version: 2.3.7
最后更新: 2026-03-26 03:15 最后更新: 2026-03-26 05:49
模块数量: 4 模块数量: 4
待执行方案: 4 待执行方案: 5
``` ```
## 读取指引 ## 读取指引
@@ -0,0 +1 @@
{"status":"completed","completed":3,"failed":0,"pending":0,"total":3,"done":3,"percent":100,"current":"已完成文件管理器右键菜单关闭竞态修复","updated_at":"2026-03-26 05:49:00"}
@@ -0,0 +1,72 @@
# 变更提案: 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。
**理由**: 根因在关闭时序,不在菜单项自身;统一到组件层能最小化改动同时保证内部点击不再被抢先吞掉。
**影响**: 仅影响文件管理器右键菜单关闭链路,不改动终端/上传/压缩业务实现。
@@ -0,0 +1,45 @@
# 任务清单: file-manager-context-submenu-regression
```yaml
@feature: file-manager-context-submenu-regression
@created: 2026-03-26
@status: completed
@mode: R2
```
## 进度概览
| 完成 | 失败 | 跳过 | 总数 |
|------|------|------|------|
| 3 | 0 | 0 | 3 |
---
## 任务列表
### 1. 方案与根因确认
- [√] 1.1 创建回归修复方案包并锁定到文件管理器右键菜单链路 | depends_on: []
### 2. 菜单关闭竞态修复
- [√] 2.1 移除捕获阶段的全局关闭监听,保留组件层 click-outside 作为唯一关闭入口 | depends_on: [1.1]
- [√] 2.2 回归检查普通菜单点击、子菜单展开和空白处关闭行为 | depends_on: [2.1]
### 3. 验证与知识库同步
- [√] 3.1 运行前端定向验证并同步 CHANGELOG/归档记录 | depends_on: [2.2]
---
## 执行日志
| 时间 | 任务 | 状态 | 备注 |
|------|------|------|------|
| 2026-03-26 05:27 | 1.1 | 完成 | 创建 implementation 方案包,范围锁定为文件管理器右键子菜单点击无反应的回归修复 |
| 2026-03-26 05:33 | 2.1 | 完成 | 删除 `useFileManagerContextMenu.ts` 中捕获阶段的全局点击关闭监听,避免菜单内部点击前被提前销毁 |
| 2026-03-26 05:36 | 2.2 | 完成 | 复核组件层 `handleClickOutside` 仍负责菜单外部关闭,普通菜单项与子菜单交互路径保持分离 |
| 2026-03-26 05:49 | 3.1 | 完成 | `npm run build --workspace @nexus-terminal/frontend` 通过,并同步 frontend 模块文档与 CHANGELOG |
---
## 执行备注
> 当前任务已完成,修复范围保持在文件管理器右键菜单关闭竞态,不涉及终端、上传或压缩业务逻辑重写。
+2
View File
@@ -7,6 +7,7 @@
| 时间戳 | 名称 | 类型 | 涉及模块 | 决策 | 结果 | | 时间戳 | 名称 | 类型 | 涉及模块 | 决策 | 结果 |
|--------|------|------|---------|------|------| |--------|------|------|---------|------|------|
| 202603260527 | file-manager-context-submenu-regression | implementation | frontend | file-manager-context-submenu-regression#D001 | ✅完成 |
| 202603260324 | file-manager-delete-upload-stability | implementation | frontend, backend | file-manager-delete-upload-stability#D001 | ✅完成 | | 202603260324 | file-manager-delete-upload-stability | implementation | frontend, backend | file-manager-delete-upload-stability#D001 | ✅完成 |
| 202603260310 | file-manager-root-sibling-bootstrap | implementation | frontend | file-manager-root-sibling-bootstrap#D001 | ✅完成 | | 202603260310 | file-manager-root-sibling-bootstrap | implementation | frontend | file-manager-root-sibling-bootstrap#D001 | ✅完成 |
| 202603260234 | folder-upload-auto-zip | implementation | frontend | folder-upload-auto-zip#D001 | ✅完成 | | 202603260234 | folder-upload-auto-zip | implementation | frontend | folder-upload-auto-zip#D001 | ✅完成 |
@@ -39,6 +40,7 @@
## 按月归档 ## 按月归档
### 2026-03 ### 2026-03
- [202603260527_file-manager-context-submenu-regression](./2026-03/202603260527_file-manager-context-submenu-regression/) - 修复文件管理器右键菜单回归关闭竞态,恢复终端、上传、压缩等子菜单展开与点击
- [202603260324_file-manager-delete-upload-stability](./2026-03/202603260324_file-manager-delete-upload-stability/) - 修复文件管理器右键子菜单点击、拖拽上传目标确认、目录删除模式选择与删除后路径失效回退 - [202603260324_file-manager-delete-upload-stability](./2026-03/202603260324_file-manager-delete-upload-stability/) - 修复文件管理器右键子菜单点击、拖拽上传目标确认、目录删除模式选择与删除后路径失效回退
- [202603260234_folder-upload-auto-zip](./2026-03/202603260234_folder-upload-auto-zip/) - 为文件管理器补齐上传文件夹入口,选择目录后先打包为 zip,再上传并自动触发远端解压 - [202603260234_folder-upload-auto-zip](./2026-03/202603260234_folder-upload-auto-zip/) - 为文件管理器补齐上传文件夹入口,选择目录后先打包为 zip,再上传并自动触发远端解压
- [202603260228_file-context-menu-terminal-actions](./2026-03/202603260228_file-context-menu-terminal-actions/) - 重排文件区右键菜单结构,并补齐终端子菜单、复制文件名和复制绝对路径等动作 - [202603260228_file-context-menu-terminal-actions](./2026-03/202603260228_file-context-menu-terminal-actions/) - 重排文件区右键菜单结构,并补齐终端子菜单、复制文件名和复制绝对路径等动作
File diff suppressed because one or more lines are too long
+8 -12
View File
@@ -3,7 +3,7 @@
<div align="center"> <div align="center">
[![Docker](https://img.shields.io/badge/-Docker-2496ED?style=flat-square&logo=docker&logoColor=white)][docker-url] [![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-4CAF50?style=flat-square)](https://github.com/Heavrnl/nexus-terminal/blob/main/LICENSE) [![Docker](https://img.shields.io/badge/-Docker-2496ED?style=flat-square&logo=docker&logoColor=white)][docker-url] [![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-4CAF50?style=flat-square)](https://github.com/Micah123321/nexus-terminal/blob/main/LICENSE)
<br> <br>
[中文](./README.md) | [English](./doc/README_EN.md) [中文](./README.md) | [English](./doc/README_EN.md)
@@ -16,6 +16,9 @@
**星枢终端(Nexus Terminal** 是一款现代化、功能丰富的 Web SSH / RDP / VNC 客户端,致力于提供高度可定制的远程连接体验。提供独立的本地桌面端。 **星枢终端(Nexus Terminal** 是一款现代化、功能丰富的 Web SSH / RDP / VNC 客户端,致力于提供高度可定制的远程连接体验。提供独立的本地桌面端。
当前维护仓库:[`Micah123321/nexus-terminal`](https://github.com/Micah123321/nexus-terminal)
源项目:[`Heavrnl/nexus-terminal`](https://github.com/Heavrnl/nexus-terminal)
## 🧱 项目结构 ## 🧱 项目结构
本仓库采用 `npm workspaces` 的 monorepo 结构: 本仓库采用 `npm workspaces` 的 monorepo 结构:
@@ -69,7 +72,7 @@
> 移除了web端的特有功能,如各种登录验证,会话挂起等功能 > 移除了web端的特有功能,如各种登录验证,会话挂起等功能
https://github.com/Heavrnl/nexus-terminal/releases/latest https://github.com/Micah123321/nexus-terminal/releases/latest
## 🚀 快速开始 ## 🚀 快速开始
@@ -83,9 +86,9 @@ mkdir ./nexus-terminal && cd ./nexus-terminal
``` ```
下载仓库中的 [**docker-compose.yml**](https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/docker-compose.yml) 和 [**.env**](https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/.env) 文件到当前目录。 下载仓库中的 [**docker-compose.yml**](https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/docker-compose.yml) 和 [**.env**](https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/.env) 文件到当前目录。
```bash ```bash
wget https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/docker-compose.yml -O docker-compose.yml && wget https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/.env -O .env wget https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/docker-compose.yml -O docker-compose.yml && wget https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/.env -O .env
``` ```
> ⚠️ **注意:** > ⚠️ **注意:**
> >
@@ -192,7 +195,7 @@ docker compose up -d
1. **双文件管理器**:可以在布局中添加两个文件管理器组件(实验性功能,可能存在不稳定情况)。 1. **双文件管理器**:可以在布局中添加两个文件管理器组件(实验性功能,可能存在不稳定情况)。
2. **多文本编辑器**:在同一布局中添加多个文本编辑器的功能尚未实现。 2. **多文本编辑器**:在同一布局中添加多个文本编辑器的功能尚未实现。
3. ARMv7 用户请使用此处的 [docker-compose.yml](https://github.com/Heavrnl/nexus-terminal/blob/main/doc/arm/docker-compose.yml)。由于 Apache Guacamole 未提供 guacd 的 ARMv7 架构镜像,所以禁用 RDP 功能,相关镜像暂时不再拉取。 3. ARMv7 用户请使用此处的 [docker-compose.yml](https://github.com/Micah123321/nexus-terminal/blob/main/doc/arm/docker-compose.yml)。由于 Apache Guacamole 未提供 guacd 的 ARMv7 架构镜像,所以禁用 RDP 功能,相关镜像暂时不再拉取。
4. 关于数据备份,请自行备份目录下的 data 文件夹,本项目不提供相关备份功能。 4. 关于数据备份,请自行备份目录下的 data 文件夹,本项目不提供相关备份功能。
5. 由于浏览器限制,非https或者localhost无法复制终端内容,请使用https访问 5. 由于浏览器限制,非https或者localhost无法复制终端内容,请使用https访问
@@ -219,13 +222,6 @@ npm run build --workspace=@nexus-terminal/remote-gateway
* 预设主题方案来源于优秀的 [iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes) 项目。 * 预设主题方案来源于优秀的 [iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes) 项目。
## ☕ 捐赠
如果你觉得这个项目对你有帮助,欢迎通过以下方式请我喝杯咖啡:
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/0heavrnl)
## 📄 开源协议 ## 📄 开源协议
本项目采用 [GPL-3.0](LICENSE) 开源协议,详细信息请参阅 [LICENSE](LICENSE) 文件。 本项目采用 [GPL-3.0](LICENSE) 开源协议,详细信息请参阅 [LICENSE](LICENSE) 文件。
+8 -12
View File
@@ -4,7 +4,7 @@
<div align="center"> <div align="center">
[![Docker](https://img.shields.io/badge/-Docker-2496ED?style=flat-square&logo=docker&logoColor=white)][docker-url] [![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-4CAF50?style=flat-square)](https://github.com/Heavrnl/nexus-terminal/blob/main/LICENSE) [![Docker](https://img.shields.io/badge/-Docker-2496ED?style=flat-square&logo=docker&logoColor=white)][docker-url] [![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-4CAF50?style=flat-square)](https://github.com/Micah123321/nexus-terminal/blob/main/LICENSE)
<br> <br>
[中文](../README.md) | [English](./README_EN.md) [中文](../README.md) | [English](./README_EN.md)
@@ -18,6 +18,9 @@
**Nexus Terminal** is a modern, feature-rich web-based SSH / RDP / VNC client dedicated to providing a highly customizable remote connection experience. A standalone desktop client is also available. **Nexus Terminal** is a modern, feature-rich web-based SSH / RDP / VNC client dedicated to providing a highly customizable remote connection experience. A standalone desktop client is also available.
Maintained fork: [`Micah123321/nexus-terminal`](https://github.com/Micah123321/nexus-terminal)
Upstream source project: [`Heavrnl/nexus-terminal`](https://github.com/Heavrnl/nexus-terminal)
## 🧱 Project Structure ## 🧱 Project Structure
This repository uses an `npm workspaces` monorepo layout: This repository uses an `npm workspaces` monorepo layout:
@@ -70,7 +73,7 @@ This repository uses an `npm workspaces` monorepo layout:
> Removed web-specific features such as various login verifications and session suspension. > Removed web-specific features such as various login verifications and session suspension.
https://github.com/Heavrnl/nexus-terminal/releases/latest https://github.com/Micah123321/nexus-terminal/releases/latest
## 🚀 Quick Start ## 🚀 Quick Start
@@ -85,11 +88,11 @@ mkdir ./nexus-terminal && cd ./nexus-terminal
--- ---
Download the [**docker-compose.yml**](https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/docker-compose.yml) and [**.env**](https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/.env) files from the repository to your current directory. Download the [**docker-compose.yml**](https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/docker-compose.yml) and [**.env**](https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/.env) files from the repository to your current directory.
```bash ```bash
wget https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/docker-compose.yml -O docker-compose.yml && wget https://raw.githubusercontent.com/Heavrnl/nexus-terminal/refs/heads/main/.env -O .env wget https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/docker-compose.yml -O docker-compose.yml && wget https://raw.githubusercontent.com/Micah123321/nexus-terminal/refs/heads/main/.env -O .env
``` ```
@@ -198,7 +201,7 @@ You can right-click in the SSH tab to select "Suspend Session" (long-press on mo
1. **Dual File Managers**: You can add two file manager components in the layout (experimental feature, may be unstable). 1. **Dual File Managers**: You can add two file manager components in the layout (experimental feature, may be unstable).
2. **Multiple Text Editors**: The functionality to add multiple text editors in the same layout has not yet been implemented. 2. **Multiple Text Editors**: The functionality to add multiple text editors in the same layout has not yet been implemented.
3. For **ARMv7** users, please use the [docker-compose.yml](https://github.com/Heavrnl/nexus-terminal/blob/main/doc/arm/docker-compose.yml) provided here. 3. For **ARMv7** users, please use the [docker-compose.yml](https://github.com/Micah123321/nexus-terminal/blob/main/doc/arm/docker-compose.yml) provided here.
Since Apache Guacamole does not provide an ARMv7-compatible image for `guacd`, the RDP/VNC feature has been disabled, and related images will not be pulled for now. Since Apache Guacamole does not provide an ARMv7-compatible image for `guacd`, the RDP/VNC feature has been disabled, and related images will not be pulled for now.
4. Since I don't have an ARM machine on hand, I haven't conducted actual testing, so unexpected bugs may occur during runtime. 4. Since I don't have an ARM machine on hand, I haven't conducted actual testing, so unexpected bugs may occur during runtime.
5. For data backup, please back up the **data** folder in the directory yourself. This project does not provide any backup functionality. 5. For data backup, please back up the **data** folder in the directory yourself. This project does not provide any backup functionality.
@@ -226,13 +229,6 @@ The `.helloagents/` directory stores the local knowledge base, module index, and
* The preset theme schemes are based on the excellent [iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes) project. * The preset theme schemes are based on the excellent [iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes) project.
## ☕ Donate
If you find this project helpful, feel free to buy me a coffee through the following ways:
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/0heavrnl)
## 📄 License ## 📄 License
This project is licensed under the [GPL-3.0](LICENSE) license. See the [LICENSE](LICENSE) file for details. This project is licensed under the [GPL-3.0](LICENSE) license. See the [LICENSE](LICENSE) file for details.
@@ -331,13 +331,6 @@ export function useFileManagerContextMenu(options: UseFileManagerContextMenuOpti
contextMenuPosition.value = { x: finalX, y: finalY }; contextMenuPosition.value = { x: finalX, y: finalY };
} }
// Add global listener to hide menu *after* positioning
document.removeEventListener('click', hideContextMenu, { capture: true });
document.addEventListener('click', hideContextMenu, { capture: true, once: true });
} else {
// Fallback listener if measurement fails
document.removeEventListener('click', hideContextMenu, { capture: true });
document.addEventListener('click', hideContextMenu, { capture: true, once: true });
} }
}); });
}; };
@@ -347,7 +340,6 @@ export function useFileManagerContextMenu(options: UseFileManagerContextMenuOpti
contextMenuVisible.value = false; contextMenuVisible.value = false;
contextMenuItems.value = []; contextMenuItems.value = [];
contextTargetItem.value = null; // 清理目标项 contextTargetItem.value = null; // 清理目标项
document.removeEventListener('click', hideContextMenu, { capture: true });
}; };
// 返回需要暴露的状态和方法 // 返回需要暴露的状态和方法