大家好呀~ 我是一个普通的前端菜鸡,最近在做后台管理系统时,遇到了组织架构选择的需求。虽然 Element UI 提供了 Tree 和 Select 组件,但要把它们完美结合还是有点小挑战的。经过一番折腾,总算搞出了一个勉强能用的树形选择器,今天就跟大家分享一下这个"不太完美但还能凑合"的实现方案 😅
效果如下:
选中时,居中回显
支持下拉搜索
功能特点
-
支持树形数据展示
-
支持搜索过滤
-
支持清空选择
-
自动定位到选中节点
-
支持懒加载
-
优化的滚动性能
-
1. 组件结构
组件采用 el-select + el-tree 的嵌套结构:
<el-select
v-model="selectValue"
placeholder="请选择组织"
filterable
clearable
style="width: 100%;"
@change="handleChange"
:filter-method="filterOrg"
@clear="handleClear"
@visible-change="handleVisibleChange"
:no-data-text="loading ? '加载中...' : '暂无数据'"
>
<el-option :value="selectValue" style="height: auto;padding: 0;border: 0;">
<div v-loading="loading" class="tree-container" ref="treeContainer">
<el-tree
ref="orgTree"
:data="options"
:props="{
children: 'children',
label: 'fullName'
}"
node-key="fullName"
highlight-current
:filter-node-method="filterNode"
@node-click="handleNodeClick"
:current-node-key="selectValue"
default-expand-all
>
</el-tree>
</div>
</el-option>
</el-select>
2. 数据加载
async getOrgList() {
this.loading = true
try {
const res = await getOrganizeSelector()
this.options = res.data.list
} catch (error) {
this.$message.error('获取组织列表失败')
} finally {
this.loading = false
}
}
3. 搜索过滤实现
filterNode(value, data) {
if (!value) return true
return data.fullName.toLowerCase().indexOf(value.toLowerCase()) !== -1
}
filterOrg(val) {
this.$refs.orgTree.filter(val || '')
return true
}
4. 自动定位功能
handleVisibleChange(visible) {
if (visible && this.selectValue) {
setTimeout(() => {
const node = this.$refs.orgTree.getNode(this.selectValue)
if (node) {
// 展开所有父节点
let parent = node.parent
while (parent && parent.level > 0) {
parent.expanded = true
parent = parent.parent
}
// 滚动到选中节点
this.$nextTick(() => {
const element = this.$refs.treeContainer.querySelector(
'.el-tree-node.is-current > .el-tree-node__content'
)
if (element) {
element.scrollIntoView({ block: 'center' })
}
})
}
}, 100)
}
}
样式优化
.tree-container {
height: 240px;
overflow-y: auto;
background-color: #fff;
}
::v-deep {
.el-tree-node__content {
height: 32px;
font-weight: normal;
}
.el-tree-node.is-current > .el-tree-node__content {
background-color: #f5f7fa;
color: #409EFF;
}
}
使用方法
<template>
<tree-select
v-model="selectedOrg"
@select="handleOrgSelect"
@clear="handleOrgClear"
/>
</template>
<script>
export default {
data() {
return {
selectedOrg: ''
}
},
methods: {
handleOrgSelect(data) {
console.log('选中组织:', data)
},
handleOrgClear() {
console.log('清空选择')
}
}
}
</script>
注意事项
-
组件初始化时需要处理 value 值的同步
-
清空选择时需要同时处理 tree 和 select 的状态
-
搜索过滤时需要考虑大小写敏感性
-
自动定位功能需要考虑异步加载的情况