效果:

大致思路:
el-select和el-tree进行嵌套,将el-tree放到el-option里,循环遍历el-option,同时定义一个方法比如:formatData,对树形数据进行递归处理,这样就可以实现无论嵌套的层级有几层都可以正常渲染在界面上 利用 v-model 和 update:selectValue 实现父子组件之间的双向通信,同时利用computed进行监听
vue
子组件:TreeSelect.vue
xml
<template>
<div class="app-container" style="padding: 0">
<el-select
class="main-select-tree"
ref="selectTree"
v-model="value"
style="width: 240px"
clearable
@clear="clearSelectInput"
>
<el-input
style="width: 220px; margin-left: 10px; margin-bottom: 10px"
placeholder="输入关键字进行过滤"
v-model="filterText"
clearable
>
</el-input>
<el-option
v-for="item in formatData(data)"
:key="item.value"
:label="item.label"
:value="item.value"
style="display: none"
/>
<el-tree
class="main-select-el-tree"
ref="selecteltree"
:data="data"
node-key="id"
highlight-current
:props="defaultProps"
@node-click="handleNodeClick"
:current-node-key="value"
:expand-on-click-node="true"
default-expand-all
:filter-node-method="filterNode"
/>
</el-select>
</div>
</template>
<script>
export default {
props: {
selectValue: {
type: String,
default: "",
},
},
data() {
return {
filterText: "",
value: "",
data: [
{
id: 1,
label: "云南",
children: [
{
id: 2,
label: "昆明",
children: [
{
id: 3,
label: "五华区",
children: [
{
id: 8,
label: "xx街道",
children: [
{
id: 81,
label: "yy社区",
children: [{ id: 82, label: "北辰小区" }],
},
],
},
],
},
{ id: 4, label: "盘龙区" },
],
},
],
},
{
id: 5,
label: "湖南",
children: [
{ id: 6, label: "长沙" },
{ id: 7, label: "永州" },
],
},
{
id: 12,
label: "重庆",
children: [
{ id: 10, label: "渝北" },
{ id: 9, label: "合川" },
],
},
{
id: 13,
label: "江苏",
children: [{ id: 14, label: "盐城" }],
},
],
defaultProps: {
children: "children",
label: "label",
},
};
},
watch: {
filterText(val) {
this.$refs.selecteltree.filter(val);
},
},
methods: {
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
// 递归遍历数据
formatData(data) {
let options = [];
const formatDataRecursive = (data) => {
data.forEach((item) => {
options.push({ label: item.label, value: item.id });
if (item.children && item.children.length > 0) {
formatDataRecursive(item.children);
}
});
};
formatDataRecursive(data);
return options;
},
// 点击事件
handleNodeClick(node) {
this.value = node.id;
this.$refs.selectTree.blur();
this.$emit('update:selectValue', node.label);
},
// 清空事件
clearSelectInput() {
this.$emit('update:selectValue', '');
},
},
};
</script>
<style>
.main-select-el-tree .el-tree-node .is-current > .el-tree-node__content {
font-weight: bold;
color: #409eff;
}
.main-select-el-tree .el-tree-node.is-current > .el-tree-node__content {
font-weight: bold;
color: #409eff;
}
</style>
父组件:
vue
<TreeSelect v-model="selectedValue" @update:selectValue="handleSelectValueChange"></TreeSelect>
<el-button size="medium" :disabled="todoIsTotal">交接当前{{ tableData.length }}条任务</el-button>
import TreeSelect from "./TreeSelect.vue";
export default {
components: {
TreeSelect,
},
data() {
selectedValue: "",
},
computed: {
todoIsTotal() {
return this.selectedValue === "";
},
},
methods: {
handleSelectValueChange(value) {
if (value && value.length > 0) {
this.selectedValue = value;
} else {
this.selectedValue = "";
}
},
},
}