vue实现tree
Vue 实现 Tree 组件
使用递归组件实现树形结构
递归组件是 Vue 中实现树形结构的常见方法。通过组件调用自身来渲染子节点。
<template>
<div>
<tree-node :node="treeData"></tree-node>
</div>
</template>
<script>
export default {
components: {
TreeNode: {
name: 'TreeNode',
props: ['node'],
template: `
<div>
<div @click="toggle">
{{ node.label }}
</div>
<div v-show="expanded" v-if="node.children">
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child">
</tree-node>
</div>
</div>
`,
data() {
return {
expanded: false
}
},
methods: {
toggle() {
this.expanded = !this.expanded
}
}
}
},
data() {
return {
treeData: {
id: 1,
label: 'Root',
children: [
{
id: 2,
label: 'Child 1',
children: [
{id: 3, label: 'Grandchild 1'},
{id: 4, label: 'Grandchild 2'}
]
},
{
id: 5,
label: 'Child 2'
}
]
}
}
}
}
</script>
使用第三方库
对于更复杂的需求,可以考虑使用成熟的第三方 Tree 组件库:
-
Element UI 的 Tree 组件:

<el-tree :data="data" show-checkbox node-key="id" :default-expanded-keys="[2, 3]" :default-checked-keys="[5]"> </el-tree> -
Vue Ant Design 的 Tree 组件:
<a-tree v-model:checkedKeys="checkedKeys" checkable :tree-data="treeData" @check="onCheck" /> -
Vuetify 的 TreeView 组件:

<v-treeview :items="items" activatable open-on-click ></v-treeview>
实现可拖拽的树
通过 HTML5 的拖拽 API 或第三方库实现拖拽功能:
<template>
<div>
<tree-node
v-for="node in treeData"
:key="node.id"
:node="node"
@node-drop="handleDrop">
</tree-node>
</div>
</template>
<script>
export default {
methods: {
handleDrop(draggedNode, targetNode) {
// 处理节点拖拽逻辑
}
}
}
</script>
树组件的关键功能实现
- 展开/折叠:通过 v-show 或 v-if 控制子节点显示
- 复选框:维护选中的节点 ID 数组
- 懒加载:监听节点展开事件,动态加载子节点
- 搜索过滤:通过 computed 属性过滤可见节点
- 自定义节点内容:通过作用域插槽实现
性能优化
对于大型树结构,考虑以下优化措施:
- 虚拟滚动(只渲染可见区域的节点)
- 分批次加载数据
- 使用 keep-alive 缓存已渲染节点
- 避免深层响应式数据
完整示例
<template>
<div class="tree-container">
<div
v-for="node in visibleNodes"
:key="node.id"
:style="{ 'padding-left': (node.level * 20) + 'px' }">
<div class="node" @click="toggleExpand(node)">
<span v-if="node.children">
{{ node.expanded ? '▼' : '▶' }}
</span>
<span>{{ node.label }}</span>
</div>
<tree-node
v-if="node.expanded && node.children"
:nodes="node.children"
:level="node.level + 1">
</tree-node>
</div>
</div>
</template>
<script>
export default {
name: 'TreeNode',
props: {
nodes: Array,
level: {
type: Number,
default: 0
}
},
computed: {
visibleNodes() {
return this.nodes.filter(node => !node.hidden)
}
},
methods: {
toggleExpand(node) {
this.$set(node, 'expanded', !node.expanded)
}
}
}
</script>
<style>
.tree-container {
font-family: Arial, sans-serif;
}
.node {
cursor: pointer;
padding: 5px;
&:hover {
background-color: #f0f0f0;
}
}
</style>






