一、演示效果
二、完整代码
<template>
<el-popover
placement="bottom-start"
title=""
width="300"
v-model="showTree"
popper-class="el-popover-tree"
trigger="click"
content="">
<el-input class="dataset-tree-picker"
v-model="showValue"
placeholder="请选择"
clearable
@focus="handleFocus"
@blur="handleBlur"
@change="handleChange"
:suffix-icon="showIcon"
slot="reference" />
<div class="dataset-tree-picker__content">
<el-tree :data="tree"
ref="tree"
:node-key="props.key"
v-loading="loading"
:props="props"
:default-expanded-keys="expandedKeys"
:default-checked-keys="checkedKeys"
:filter-node-method="filterNode"
@node-click="handleNodeClick"></el-tree>
</div>
</el-popover>
</template>
<script>
export default {
name: 'info-config-tree',
data () {
return {
init: false,
showTree: false, // 显示隐藏目录树
canFilter: false, // 目录树是否支持搜索
loading: false, // 当前选择的节点
expandedKeys: [], // 默认展开的节点的key的数组
checkedKeys: [], // 默认勾选的节点的key的数组
selected: {},
showValue: '', // input框显示的中文值
// 目录树配置项
props: {
key: 'Id',
label: 'Label',
children: 'ChildNodes',
isLeaf: 'HasChildren'
},
// 目录树数据
tree: [
{
Enable: false,
HasChildren: true,
Id: '44',
NodeId: 448,
OrderNum: 1,
Parent: true,
Label: '广东省',
ChildNodes: [
{
Enable: false,
HasChildren: true,
Id: '4401',
NodeId: 449,
OrderNum: 1,
Parent: true,
ParentId: '44',
ParentLabel: '广东省',
Label: '广州市',
ChildNodes: [
{
Enable: false,
HasChildren: false,
Id: '440103',
NodeId: 450,
OrderNum: 1,
Parent: true,
ParentId: '4401',
ParentLabel: '广州市',
Label: '荔湾区',
ChildNodes: []
},
{
Enable: false,
HasChildren: false,
Id: '440104',
NodeId: 479,
OrderNum: 1,
Parent: true,
ParentId: '4401',
ParentLabel: '广州市',
Label: '越秀区',
ChildNodes: []
}
]
},
{
Enable: false,
HasChildren: false,
Id: '4403',
NodeId: 1017,
OrderNum: 1,
Parent: true,
ParentId: '44',
ParentLabel: '广东省',
Label: '深圳市',
ChildNodes: []
}
]
}
]
};
},
computed: {
// input尾部显示上下箭头icon
showIcon () {
if (this.showValue !== '') {
return '';
} else {
return this.showTree ? 'el-icon-arrow-up' : 'el-icon-arrow-down';
}
}
},
watch: {
// 监听input框值变化,如果当前状态是搜索,则调用目录树搜索方法
showValue (val) {
if (!this.canFilter) {
return;
}
this.$refs.tree.filter(val);
}
},
created () {
this.getTreeList();
},
methods: {
// 通过key设置某个节点的当前选中状态
async setCurrentKey (id) {
await this.getTreeList();
this.$nextTick(() => {
const node = this.$refs.tree.getNode(id);
if (node) {
this.expandedKeys = this.getDefaultExpandedKeys(this.tree, id);
this.$refs.tree.setCurrentKey(id);
this.selected = node.data;
this.showValue = this.selected[this.props.label];
return this.selected;
}
});
},
// 默认展开
getDefaultExpandedKeys (tree, id, keys = []) {
for (let i = 0, len = tree.length; i < len; i++) {
const item = tree[i];
if (item[this.props.key] === id) {
keys.push(item[this.props.key]);
return keys;
}
if (item[this.props.children] && item[this.props.children].length) {
const temp = this.getDefaultExpandedKeys(item[this.props.children], id, keys);
temp.length && (keys = keys.concat(temp));
}
}
return keys;
},
// input框值改变
handleChange (val) {
this.$emit('change', '');
},
// input聚焦
handleFocus () {
this.showValue = '';
this.canFilter = true;
},
// input失去焦点
handleBlur () {
this.canFilter = false;
this.showValue = this.selected[this.props.label];
},
// 对树节点进行筛选时执行的方法
filterNode (value, data) {
if (!value) return true;
return (data[this.props.label] || '').toLowerCase().indexOf((value || '').toLowerCase()) !== -1;
},
// 节点点击事件
handleNodeClick (data) {
if (data[this.props.key]) {
this.selected = data;
this.showValue = data[this.props.label];
this.$emit('change', data[this.props.key]); // 发送给父组件
this.showTree = false;
}
},
// 默认展开和选中第一项
setExpandDefault (tree = this.tree) {
let firstItem = tree.find(d => {
return d && (d[this.props.children] || []).length;
});
if (!firstItem) {
firstItem = tree[0];
}
if (!firstItem) return;
this.expandedKeys.push(firstItem[this.props.key]);
this.checkedKeys.push(firstItem[this.props.key]);
this.handleNodeClick(firstItem);
},
// 接口获取数据源树
async getTreeList () {
try {
// 接口获取 当前为了测试在data写死了目录树数据
// if (this.init) {
// return;
// }
// this.loading = true;
// const result = await this.$api.getTreeList();
// this.tree = result.Data;
if (!this.init) {
this.$nextTick(() => {
this.expandedKeys = [];
this.checkedKeys = [];
this.setExpandDefault();
});
}
this.init = true;
} catch (error) {
console.log(error);
} finally {
this.loading = false;
}
}
}
};
</script>
<style lang="scss">
.dataset-tree-picker {
&__content {
max-height: 500px;
overflow: auto;
.el-tree {
&-node {
&.is-current {
& > .el-tree-node__content {
background: $--color-primary-light-1;
}
}
}
}
}
}
</style>