vue树形菜单实现
Vue 树形菜单实现方法
使用递归组件实现树形结构
递归组件是 Vue 中实现树形菜单的常见方式。通过组件自身调用自身,可以轻松处理嵌套的树形数据。
<template>
<ul>
<li v-for="item in treeData" :key="item.id">
{{ item.label }}
<tree-menu v-if="item.children" :treeData="item.children"></tree-menu>
</li>
</ul>
</template>
<script>
export default {
name: 'TreeMenu',
props: {
treeData: {
type: Array,
required: true
}
}
}
</script>
添加展开/折叠功能
为树形菜单添加交互功能,允许用户展开或折叠子菜单。
<template>
<ul>
<li v-for="item in treeData" :key="item.id">
<span @click="toggle(item)">
{{ item.expanded ? '▼' : '►' }} {{ item.label }}
</span>
<tree-menu
v-if="item.children && item.expanded"
:treeData="item.children"
></tree-menu>
</li>
</ul>
</template>
<script>
export default {
name: 'TreeMenu',
props: {
treeData: Array
},
methods: {
toggle(item) {
this.$set(item, 'expanded', !item.expanded)
}
}
}
</script>
使用第三方库
对于更复杂的需求,可以考虑使用专门处理树形结构的 Vue 组件库。
安装 element-ui 的树形组件:
npm install element-ui
使用示例:
<template>
<el-tree
:data="treeData"
:props="defaultProps"
@node-click="handleNodeClick"
></el-tree>
</template>
<script>
import { ElTree } from 'element-ui'
export default {
components: {
ElTree
},
data() {
return {
treeData: [{
label: '一级 1',
children: [{
label: '二级 1-1'
}]
}],
defaultProps: {
children: 'children',
label: 'label'
}
}
},
methods: {
handleNodeClick(data) {
console.log(data)
}
}
}
</script>
动态加载数据
对于大型树形结构,可以实现懒加载功能,只在展开时加载子节点数据。
<template>
<ul>
<li v-for="item in treeData" :key="item.id">
<span @click="loadChildren(item)">
{{ item.hasChildren ? (item.expanded ? '▼' : '►') : '' }} {{ item.label }}
</span>
<tree-menu
v-if="item.children && item.expanded"
:treeData="item.children"
></tree-menu>
</li>
</ul>
</template>
<script>
export default {
methods: {
async loadChildren(item) {
if (!item.expanded && item.hasChildren && !item.children) {
const children = await fetchChildren(item.id)
this.$set(item, 'children', children)
}
this.$set(item, 'expanded', !item.expanded)
}
}
}
</script>
样式优化
为树形菜单添加基本样式,提升用户体验。
ul {
list-style-type: none;
padding-left: 20px;
}
li {
margin: 5px 0;
cursor: pointer;
}
span:hover {
background-color: #f5f5f5;
}
完整示例
结合上述功能的完整树形菜单组件示例:
<template>
<ul class="tree-menu">
<li v-for="item in treeData" :key="item.id">
<div class="node" @click="toggleNode(item)">
<span class="toggle-icon">
{{ item.children && item.children.length ? (item.expanded ? '▼' : '►') : '' }}
</span>
<span class="node-label">{{ item.label }}</span>
</div>
<tree-menu
v-if="item.children && item.expanded"
:treeData="item.children"
class="sub-tree"
></tree-menu>
</li>
</ul>
</template>
<script>
export default {
name: 'TreeMenu',
props: {
treeData: {
type: Array,
required: true
}
},
methods: {
toggleNode(item) {
this.$set(item, 'expanded', !item.expanded)
}
}
}
</script>
<style scoped>
.tree-menu {
list-style: none;
padding-left: 20px;
}
.node {
display: flex;
align-items: center;
padding: 5px 0;
cursor: pointer;
}
.toggle-icon {
display: inline-block;
width: 20px;
}
.node-label {
margin-left: 5px;
}
.node:hover {
background-color: #f0f0f0;
}
.sub-tree {
margin-left: 15px;
}
</style>






