我正在构建一个树组件,可以在其中移动节点。组件和数据结构与Tree View example in the Vue.js documentation中使用的组件和数据结构相似。
数据结构如下(删除了不相关的属性):
[
{"id": 1, "children": []},
{"id": 2, "children": []},
{"id": 3, "children": [
{"id": 4, "children": [
{"id": 5, "children": []},
{"id": 6, "children": []}
]}
]}
]
节点表示可以在视图中折叠或展开的“文件夹”。 FolderNode
组件如下所示:
export default {
name: 'FolderNode',
props: {
node: { type: Object, required: true },
},
data: () => ({
expanded: true,
}),
methods: {
toggleExpand() {
this.expanded = !this.expanded;
},
},
};
模板为:
<template>
<li>
<span class="node-icon">
<span @click="toggleExpand">[{{ expanded ? '-' : '+' }}]</span>
</span>
<span class="node-label">{{ node.id }}</span>
<ol
v-if="node.children && node.children.length"
v-show="expanded"
>
<FolderNode
v-for="child in node.children"
:key="child.id"
:node="child"
/>
</ol>
</li>
</template>
这部分工作正常。我添加了拖放功能以在树中四处移动节点(为简化起见,未在上面显示)。当节点被删除并插入到其他位置时,Vue.js会自动实例化新的FolderNode
组件以反映更改。将创建这些新的FolderNode
实例(将节点移至其他父节点时),其默认expanded
状态为true
。我希望:key
属性可以在不同的父级上工作,但是它只为同一父级expanded
的子级重用组件(并保持其FolderNode
状态)。
那么,移动文件夹时,如何保持文件夹的expanded
状态(和其他显示状态)?
该树对象将由应用程序的其他部分使用,因此我无法将expanded
属性直接添加到其节点,这将是最简单的解决方案。此外,expanded
严格来说是“显示状态”,与树数据无关。
我想到了2种可能并不吸引人的解决方案:
还有其他想法吗?
答案 0 :(得分:1)
构建树组件时,我们遇到了类似的问题。我们有完全相同的想法。
最初,我们创建了一个并行数据结构,借助于Ramda
,我们将合并内部数据模型外部树结构。但是事实证明这不是很优雅。而且,树协调很难实现。
但是,如果您对此方法有另一种看法,那么将expanded
作为 tree Node对象的一部分是有意义的。有很多用例:
在许多其他情况下,它被证明是有用的。我们正在使用TypeScript,我们只是将该属性声明为可选属性,例如:
export interface TreeNode<T extends any> {
label: string;
expanded: boolean;
children: Array<TreeNode<T>>;
isDisabled?: boolean;
// Holds the state if tree/node selected or not
select?: boolean;
// Unique key which identifies each node
_id?: string;
// Any other data that needs to be stored
context?: T;
}
就API而言,不必担心这些附加键,因为它们是可选的。因此,以扩展状态支持 drag-n-drop 变得很简单
答案 1 :(得分:0)
另一种可能性是不使用地图就使用选项2。实际上,该地图尽管在语义上是正确的,但实际上根本不需要!
“根”组件创建一个“树视图状态”对象,该对象保存每个节点的expanded
状态。像这样:
const treeViewState = {};
// Visit each node and create its initial view state object to make it reactive
walkNodes(tree, (node, level) => {
treeViewState[node.id] = {
expanded: level < 1, // Simple logic to only expand the first level by default
};
});
然后,“根”组件通过Vue的注入机制provide
treeViewState
为其子组件。
每个FolderNode
然后通过其节点的唯一ID访问其显示状态。这用于索引treeViewState
对象。