liubinfighter_csv-lite/docs/DEBUG_MENU_REFACTOR.md

87 lines
No EOL
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CSV Lite 插件右键菜单问题排查与重构全记录
## 背景
在开发 CSV Lite 插件的过程中遇到了表格右键菜单context menu在 UI/UX 上表现异常、事件处理混乱、菜单关闭不及时等一系列问题。为提升用户体验和代码可维护性,我们对菜单功能进行了彻底重构。本文详细记录了整个排查、修复与重构的过程。
---
## 1. 问题现象
- 右键菜单弹出后,**点击菜单项第一次不会消失,第二次才消失**。
- 菜单项 hover 效果偶尔失效。
- 菜单关闭后高亮未能及时清除。
- 控制台报错 `addClass/removeClass is not a function``tableEl.addEventListener is not a function`
- 工具栏等 UI 元素偶尔消失。
---
## 2. 初步排查
### 2.1 事件监听与 DOM 结构
- 检查菜单项点击事件,发现菜单关闭逻辑依赖于 `addClass/removeClass`,但项目中并未实现这两个方法。
- 事件监听器绑定和解绑时机混乱,可能导致多次绑定或未解绑。
### 2.2 代码实现问题
- 右键菜单相关代码分散UI 与数据操作耦合严重。
- 菜单项点击后,`closeMenu()` 并未总是被及时调用。
- 绑定菜单的时机不对,`tableEl` 可能还未渲染。
---
## 3. 修复与重构过程
### 3.1 替换 addClass/removeClass
- 将所有 `addClass/removeClass` 替换为标准的 `classList.add/classList.remove`,保证样式切换生效。
### 3.2 菜单关闭逻辑梳理
- 确保菜单项点击后立即关闭菜单,并清除高亮。
- 保证 ESC/点击外部也能关闭菜单。
### 3.3 彻底重构菜单栏功能
- 新增 `MenuManager` 类,专门负责菜单的创建、显示、关闭。
- 菜单项通过参数传递,点击后自动关闭并调用回调。
- 只在表格渲染后(即 `refresh()` 里)绑定右键菜单,确保 `tableEl` 已经是 `<table>` 元素。
- UI/UX 逻辑与数据操作彻底解耦,接口兼容原有调用方式。
### 3.4 修正绑定时机
- 移除 `onOpen` 里的菜单绑定,只在 `refresh()` 里绑定,避免 `tableEl` 未初始化时报错。
---
## 4. 最终方案
- 右键菜单功能完全由 `MenuManager` 管理UI 逻辑清晰、无副作用。
- 菜单项包括:行/列的插入、删除、交换,所有操作均通过回调传递。
- 菜单关闭时自动清除高亮,支持 ESC/点击外部关闭。
- 只在表格渲染后绑定菜单,避免 DOM 未就绪导致的报错。
- 工具栏、表格等 UI 元素全部恢复正常。
---
## 5. 经验总结
- **UI 组件应与数据操作解耦**,便于维护和扩展。
- **事件监听器的绑定和解绑时机必须严格把控**,避免内存泄漏和多次绑定。
- **DOM 操作要确保目标元素已渲染**,否则易出现 `xxx is not a function` 报错。
- **标准化样式操作**,优先使用 `classList`,避免自定义扩展污染全局。
- **重构时优先考虑单一职责原则**,如本次将菜单管理独立为 `MenuManager`
---
## 6. 参考代码片段
```ts
// 绑定菜单的正确方式
this.headerContextMenuCleanup = setupHeaderContextMenu(
this.tableEl,
{
selectRow: (rowIndex) => this.highlightManager.selectRow(rowIndex),
// ... 其他回调 ...
}
);
```
---
本次重构极大提升了插件的健壮性和用户体验,也为后续功能扩展打下了坚实基础。