6.9 KiB
6.9 KiB
name, overview, todos
| name | overview | todos | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| fix-tree-component | 修复 fms-vue 中 Tree 组件的多个缺陷:致命运行时错误(filterExpand 未定义)、受控键模型遗漏、过滤高亮缺失、键盘焦点不同步、展开交互混乱与拖拽视觉残留,并同步完善 demo。 |
|
用户需求
用户反馈 fms-vue/src/components/ui/tree 组件由上一个 AI 编写,存在较多问题,要求自检问题并修复。经过代码自检,已确认以下问题:
核心问题
- 致命错误:
tree.vue的effectiveExpandedcomputed 引用了未定义的filterExpand变量,组件渲染即抛ReferenceError,Tree 完全不可用 - Props 缺失:
useKeyModel('loadedKeys', 'defaultLoadedKeys', ...)引用了不存在的defaultLoadedKeysprop - 过滤高亮缺失:
filterTree返回的命中集合与.tree-highlight样式均未用于渲染关键词高亮 - 展开交互缺陷:展开/收起箭头被移除,无可展开视觉提示;行点击同时触发展开与选中造成误触;
toggleExpand基于effectiveExpanded会把过滤临时展开的祖先固化进用户展开集合 - 键盘导航缺陷:点击节点后未同步
activeKey与焦点,键盘导航起点错乱 - 拖拽视觉残留:
onDragLeave未清理dropKey/dropPosition,指示线残留 - 样式残留:
.tree-node.is-danger、.tree-leaf-icon等无用样式 - Demo 错乱:check-strictly 示例未绑定 checkedKeys,联动文案错标在严格模式示例下
修复范围
仅修复内部实现与 demo 演示,保持组件既有 API(props/emits/slot 名称)不变,不引入新依赖,样式沿用现有 --fms-* token。
技术栈
- Vue 3.5(
<script setup>)+ SCSS,项目现有技术栈,无需变更 - 图标使用项目已依赖的
@lucide/vue(现有导出ChevronRight、Loader、LoaderCircle) - 验证命令:
pnpm lint(oxlint)、pnpm fmt:check(oxfmt)、pnpm build(vite build)
实现方案
1. 修复致命错误与模型缺失(tree.vue)
- 删除
effectiveExpanded中对未定义filterExpand的引用,改为从filterResult.value.expand派生过滤需展开的祖先集合(computed 缓存,判空处理) - props 补充声明
defaultLoadedKeys: { type: Array, default: () => [] },与其余受控键的 default* 声明保持一致
2. 重构展开/选中交互(tree.vue + tree-node.vue + index.scss)
- 加回 switcher 箭头:
tree-node.vue行首渲染ChevronRight(展开时旋转 90°),懒加载中渲染Loader/LoaderCircle转圈;箭头@click.stop只负责toggleExpand,避免与行选中互相干扰;利用现有.tree-node-switcher/.tree-switcher-icon样式(已存在于 index.scss,仅模板缺失) toggleExpand基准改为expandedSet:基于用户展开集合增删,不再把过滤自动展开的祖先路径写回expandedKeys,清除过滤后展开状态可正确还原- 行点击只选中:
onContentClick移除隐式toggleExpand调用(展开交给箭头),消除误触 - 点击同步键盘焦点:
onContentClick中更新activeKey.value = key.value并rowRef.value.focus(),保证 roving tabindex 与键盘导航起点正确 - 键盘导航
ArrowRight/ArrowLeft保持调用toggleExpand不变
3. 实现过滤关键词高亮(tree-node.vue)
- 默认文本标题渲染时,依据
ctx.filter与filterVisible中 matched 集合,用split匹配关键词片段,命中部分用<span class="tree-highlight">包裹(大小写不敏感,与filterTree一致);自定义#title插槽场景不干预 - 高亮逻辑抽为组件内方法,避免重复计算;每次渲染仅处理当前节点标题,开销 O(title 长度),无性能问题
4. 修复拖拽残留与样式清理(tree.vue + index.scss)
onDragLeave中清空dropKey/dropPosition(仍 emitdragleave);onDragEnd已有兜底清理保留- 清理 index.scss 中未使用的
.tree-node.is-danger、.tree-leaf-icon规则(switcher 相关样式因加回箭头而保留复用)
5. 修复 Demo(demo/tree.vue)
- check-strictly 示例补充
v-model:checked-keys绑定与输出展示;"checkedKeys(联动)"文案移回联动示例下方,修正演示语义
性能与可靠性
- 全部派生状态为 computed 缓存,
effectiveExpanded修复后只依赖expandedSet+filterResult,无重复遍历 - 修改仅限 tree 组件目录与 demo 文件,不影响其他组件;无新依赖,无构建体积变化
目录结构
fms-vue/src/components/ui/tree/
├── tree.vue # [MODIFY] 修复 filterExpand 未定义;补 defaultLoadedKeys;toggleExpand 基准改为 expandedSet;
│ # onDragLeave 清理 drop 状态;onContentClick 同步 activeKey/focus
├── tree-node.vue # [MODIFY] 加回 switcher 箭头(ChevronRight/Loader,@click.stop);行点击只选中;
│ # 实现过滤关键词高亮渲染
├── index.scss # [MODIFY] 清理 .is-danger/.tree-leaf-icon 无用规则;switcher 样式保留复用
└── utils.js # [不变] 纯函数逻辑正确,无需修改
fms-vue/src/components/ui/demo/tree.vue # [MODIFY] 修正 check-strictly 示例绑定与文案
Agent Extensions
Skill
- antdv-next
- 用途:在重构展开/选中交互时,参考 Ant Design Tree 的 switcher 箭头交互、行点击与箭头职责分离、键盘导航规范,确保修复后的交互符合成熟组件库惯例
- 预期结果:展开箭头点击展开/收起、行点击仅选中、键盘 ArrowRight/ArrowLeft 行为与成熟组件库一致,避免修复后再次出现交互职责混淆