vue实现treeselect
Vue 实现 TreeSelect 组件
TreeSelect 是一种结合树形结构和下拉选择功能的组件,常用于层级数据的选择。以下是基于 Vue 2 或 Vue 3 的实现方法:
安装依赖
若使用第三方库,推荐安装 @riophae/vue-treeselect(Vue 2)或 vue-treeselect(Vue 3):
# Vue 2
npm install @riophae/vue-treeselect
# Vue 3
npm install vue-treeselect
基础用法
- 引入组件并注册:
<template> <treeselect v-model="selectedValue" :options="treeData" /> </template>
export default { components: { Treeselect }, data() { return { selectedValue: null, treeData: [ { id: 'group1', label: 'Group 1', children: [ { id: 'item1', label: 'Item 1' }, { id: 'item2', label: 'Item 2' } ] } ] } } }
```自定义配置
-
多选模式:添加
multiple属性:<treeselect v-model="selectedValues" :options="treeData" multiple /> -
异步加载:通过
load-options属性实现动态加载子节点:<treeselect v-model="selectedValue" :options="treeData" :load-options="loadOptions" async />
纯手写实现
若需完全自定义,可通过递归组件实现树形结构:
<template>
<div class="tree-select">
<input
:value="selectedLabel"
@click="toggleDropdown"
placeholder="请选择"
/>
<div v-if="isOpen" class="dropdown">
<tree-node
v-for="node in treeData"
:key="node.id"
:node="node"
@select="handleSelect"
/>
</div>
</div>
</template>
<script>
import TreeNode from './TreeNode.vue'
export default {
components: { TreeNode },
props: ['treeData'],
data() {
return {
isOpen: false,
selectedLabel: ''
}
},
methods: {
toggleDropdown() {
this.isOpen = !this.isOpen
},
handleSelect(node) {
this.selectedLabel = node.label
this.isOpen = false
this.$emit('input', node.id)
}
}
}
</script>
递归组件示例
TreeNode.vue 实现递归渲染:
<template>
<div class="node">
<div @click="toggleExpand">
{{ node.label }}
<span v-if="hasChildren">{{ isExpanded ? '-' : '+' }}</span>
</div>
<div v-if="isExpanded && hasChildren" class="children">
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child"
@select="$emit('select', $event)"
/>
</div>
</div>
</template>
<script>
export default {
name: 'TreeNode',
props: ['node'],
data() {
return {
isExpanded: false
}
},
computed: {
hasChildren() {
return this.node.children && this.node.children.length
}
},
methods: {
toggleExpand() {
if (this.hasChildren) {
this.isExpanded = !this.isExpanded
} else {
this.$emit('select', this.node)
}
}
}
}
</script>
样式优化
通过 CSS 增强交互体验:

.tree-select {
position: relative;
width: 200px;
}
.dropdown {
border: 1px solid #eee;
max-height: 300px;
overflow-y: auto;
}
.node {
padding-left: 20px;
cursor: pointer;
}
.children {
margin-left: 10px;
}
注意事项
- 数据格式需包含
id和label字段,可通过normalizer属性自定义。 - 复杂场景建议直接使用成熟库,节省开发时间。
- 手写实现时注意性能优化,避免深层递归导致渲染卡顿。






