fix: 树状视图展开文件夹为空 - 递归拍平渲染
原模板只遍历 treeData 根级节点, 从不渲染 node.children, 导致展开后为空。 改为 flattenedTree computed 将树拍平为列表: - 只包含已展开文件夹的子节点 - 每项带 level 用于缩进 (paddingLeft) - 文件夹和叶子节点在列表中按正确顺序排列 - 叶子节点支持 active/selected 高亮和右键菜单
This commit is contained in:
@@ -474,6 +474,27 @@ function isFolderExpanded(path: string): boolean {
|
|||||||
return expandedFolders.value.has(path)
|
return expandedFolders.value.has(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FlatTreeNode {
|
||||||
|
node: TreeNode
|
||||||
|
level: number
|
||||||
|
expanded: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const flattenedTree = computed<FlatTreeNode[]>(() => {
|
||||||
|
const result: FlatTreeNode[] = []
|
||||||
|
function walk(nodes: TreeNode[], level: number) {
|
||||||
|
for (const node of nodes) {
|
||||||
|
const expanded = isFolderExpanded(node.fullPath)
|
||||||
|
result.push({ node, level, expanded })
|
||||||
|
if (!node.isLeaf && expanded) {
|
||||||
|
walk(node.children, level + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walk(treeData.value, 0)
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
function isKeySelected(keyName: string): boolean {
|
function isKeySelected(keyName: string): boolean {
|
||||||
return keyStore.selectedKey === keyName && !multiSelect.value
|
return keyStore.selectedKey === keyName && !multiSelect.value
|
||||||
}
|
}
|
||||||
@@ -674,30 +695,32 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<!-- Tree View -->
|
<!-- Tree View -->
|
||||||
<div v-else class="key-tree">
|
<div v-else class="key-tree">
|
||||||
<template v-for="node in treeData" :key="node.fullPath">
|
<template v-for="item in flattenedTree" :key="item.node.fullPath">
|
||||||
<!-- Folder -->
|
<!-- Folder -->
|
||||||
<div
|
<div
|
||||||
v-if="!node.isLeaf"
|
v-if="!item.node.isLeaf"
|
||||||
class="tree-item folder-item"
|
class="tree-item folder-item"
|
||||||
@click="toggleFolder(node.fullPath)"
|
:style="{ paddingLeft: `${12 + item.level * 16}px` }"
|
||||||
|
@click="toggleFolder(item.node.fullPath)"
|
||||||
>
|
>
|
||||||
<el-icon class="tree-arrow" :class="{ expanded: isFolderExpanded(node.fullPath) }">
|
<el-icon class="tree-arrow" :class="{ expanded: item.expanded }">
|
||||||
<ArrowRight />
|
<ArrowRight />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-icon class="tree-icon folder-icon"><Folder /></el-icon>
|
<el-icon class="tree-icon folder-icon"><Folder /></el-icon>
|
||||||
<span class="tree-name">{{ formatKeyName(node.name) }}</span>
|
<span class="tree-name">{{ formatKeyName(item.node.name) }}</span>
|
||||||
<span class="tree-count">{{ node.count }}</span>
|
<span class="tree-count">{{ item.node.count }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="tree-children" :class="{ hidden: !isFolderExpanded(node.fullPath) }">
|
<!-- Leaf -->
|
||||||
<div
|
<div
|
||||||
class="tree-item leaf-item"
|
v-else
|
||||||
@click="selectKey(node.fullPath, $event)"
|
class="tree-item leaf-item"
|
||||||
@contextmenu.prevent="onKeyContextMenu($event, node.fullPath)"
|
:class="{ active: isKeySelected(item.node.fullPath), selected: isKeyMultiSelected(item.node.fullPath) }"
|
||||||
>
|
:style="{ paddingLeft: `${12 + item.level * 16}px` }"
|
||||||
<span class="tree-spacer"></span>
|
@click="selectKey(item.node.fullPath, $event)"
|
||||||
<el-icon class="tree-icon"><Document /></el-icon>
|
@contextmenu.prevent="onKeyContextMenu($event, item.node.fullPath)"
|
||||||
<span class="tree-name">{{ formatKeyName(node.name) }}</span>
|
>
|
||||||
</div>
|
<el-icon class="tree-icon"><Document /></el-icon>
|
||||||
|
<span class="tree-name">{{ formatKeyName(item.node.name) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -945,20 +968,8 @@ onUnmounted(() => {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-children {
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-children.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-spacer {
|
|
||||||
width: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf-item {
|
.leaf-item {
|
||||||
padding-left: 12px;
|
/* padding handled by inline style based on tree depth */
|
||||||
}
|
}
|
||||||
|
|
||||||
.key-footer {
|
.key-footer {
|
||||||
|
|||||||
Reference in New Issue
Block a user