Vue.js动态生成带缩进的多级Select下拉菜单教程
在后台管理系统或者需要展示层级数据的场景中,我们经常会遇到多级下拉菜单的需求,比如省市区选择、部门层级选择等。如果直接平铺所有选项,用户很难快速区分层级关系,因此给不同层级的选项添加缩进是提升体验的关键。本文将介绍如何在Vue.js中动态生成带缩进的多级Select下拉菜单,数据源支持动态配置,无需手动编写固定选项。
核心实现思路
要实现带缩进的多级Select,核心逻辑可以分为三步:
- 准备具有层级关系的树形数据,每个节点包含id、名称、子节点等信息
- 将树形数据扁平化处理,同时记录每个节点所在的层级,方便后续计算缩进量
- 在Select的选项中,根据节点的层级动态添加对应数量的缩进空格,实现视觉上的层级区分
准备树形数据源
首先我们需要准备符合层级结构的测试数据,实际项目中这个数据通常是从后端接口获取的。下面是一个简单的部门层级数据示例:
// 部门树形数据,实际项目中可从后端接口获取
const departmentTree = [
{
id: 1,
name: '总部',
children: [
{
id: 2,
name: '技术部',
children: [
{ id: 3, name: '前端组', children: [] },
{ id: 4, name: '后端组', children: [] },
{ id: 5, name: '测试组', children: [] }
]
},
{
id: 6,
name: '产品部',
children: [
{ id: 7, name: '需求组', children: [] },
{ id: 8, name: '设计组', children: [] }
]
}
]
},
{
id: 9,
name: '分公司',
children: [
{ id: 10, name: '分公司行政部', children: [] },
{ id: 11, name: '分公司业务部', children: [] }
]
}
];扁平化树形数据并计算层级
树形数据无法直接用在Select的选项渲染中,我们需要把它转换成扁平的一维数组,同时给每个节点标记上它所在的层级。这里通过一个递归函数实现:
// 扁平化树形数据,同时记录每个节点的层级
function flattenTree(treeData, level = 0, result = []) {
treeData.forEach(node => {
// 将当前节点加入结果数组,保存id、名称、层级信息
result.push({
id: node.id,
name: node.name,
level: level, // 层级从0开始,顶层为0
children: node.children // 保留子节点信息,方便后续扩展
});
// 如果有子节点,递归处理子节点,层级加1
if (node.children && node.children.length > 0) {
flattenTree(node.children, level + 1, result);
}
});
return result;
}调用这个函数后,我们会得到一个包含所有节点的扁平数组,每个节点都有对应的level属性,比如顶层部门level为0,二级部门level为1,以此类推。
Vue组件完整实现
接下来我们基于上面的逻辑,实现一个完整的Vue组件,包含动态生成选项、缩进展示、双向绑定选中值的功能:
<template>
<div class="multi-level-select">
<h3>多级部门选择</h3>
<select v-model="selectedDeptId" class="select-box">
<option value="" disabled>请选择部门</option>
<option
v-for="item in flatDeptList"
:key="item.id"
:value="item.id"
>
<!-- 根据层级添加缩进,每个层级缩进4个空格 -->
{{ ' '.repeat(item.level) }}{{ item.name }}
</option>
</select>
<p v-if="selectedDeptId">
当前选中的部门ID:{{ selectedDeptId }},部门名称:{{ selectedDeptName }}
</p>
</div>
</template>
<script>
// 树形数据定义,实际项目中可替换为接口请求获取
const departmentTree = [
{
id: 1,
name: '总部',
children: [
{
id: 2,
name: '技术部',
children: [
{ id: 3, name: '前端组', children: [] },
{ id: 4, name: '后端组', children: [] },
{ id: 5, name: '测试组', children: [] }
]
},
{
id: 6,
name: '产品部',
children: [
{ id: 7, name: '需求组', children: [] },
{ id: 8, name: '设计组', children: [] }
]
}
]
},
{
id: 9,
name: '分公司',
children: [
{ id: 10, name: '分公司行政部', children: [] },
{ id: 11, name: '分公司业务部', children: [] }
]
}
];
// 扁平化树形数据的函数
function flattenTree(treeData, level = 0, result = []) {
treeData.forEach(node => {
result.push({
id: node.id,
name: node.name,
level: level,
children: node.children
});
if (node.children && node.children.length > 0) {
flattenTree(node.children, level + 1, result);
}
});
return result;
}
export default {
name: 'MultiLevelSelect',
data() {
return {
departmentTree: departmentTree,
selectedDeptId: '',
flatDeptList: []
};
},
computed: {
// 根据选中的ID找到对应的部门名称
selectedDeptName() {
const target = this.flatDeptList.find(item => item.id === this.selectedDeptId);
return target ? target.name : '';
}
},
created() {
// 组件创建时处理树形数据,生成扁平列表
this.flatDeptList = flattenTree(this.departmentTree);
}
};
</script>
<style scoped>
.multi-level-select {
padding: 20px;
max-width: 400px;
margin: 0 auto;
}
.select-box {
width: 100%;
height: 36px;
padding: 0 10px;
font-size: 14px;
border: 1px solid #dcdfe6;
border-radius: 4px;
outline: none;
cursor: pointer;
}
.select-box:focus {
border-color: #409eff;
}
h3 {
margin-bottom: 15px;
font-size: 18px;
color: #303133;
}
p {
margin-top: 15px;
font-size: 14px;
color: #606266;
}
</style>实现细节说明
在上面的代码中,我们通过v-for遍历扁平化后的flatDeptList生成Select的选项,关键缩进的实现是通过' '.repeat(item.level)完成的:每个层级对应4个不换行空格,层级越高,重复的空格越多,视觉上就会形成缩进效果。
这里需要注意,因为是在HTML模板中渲染,所以空格要使用HTML实体 ,如果直接使用多个空格,浏览器会合并成一个,无法达到缩进效果。如果是在可编辑的内容或者预格式化文本中,也可以使用\u00A0这种Unicode空格字符,效果是一致的。
扩展场景
上面的示例是基础实现,实际项目中可以根据需求扩展:
- 如果后端返回的树形数据字段名不是id、name、children,可以在扁平化的时候做字段映射,适配不同的数据结构
- 如果需要禁用某些层级的选项,比如只允许用户选择最末级部门,可以在
<option>上添加:disabled="item.children && item.children.length > 0"的判断 - 如果数据量很大,扁平化的时候可以做缓存,避免重复处理;或者结合虚拟滚动优化Select的渲染性能
- 如果需要支持搜索过滤,可以在扁平列表的基础上做关键词匹配,过滤出符合要求的选项再渲染
通过这种方式实现的动态多级Select,不需要手动维护选项列表,数据源更新后下拉菜单会自动同步,同时缩进效果清晰展示层级关系,非常适合层级数据不固定的场景。