前言
今天小谭要给大家分享的是基于element ui 的下拉框和树型控件二次分装的树型下拉框,element plus新增了这一组件,但是对于还在使用vue2的我来说,就很不友好。组件可以实现单选和多选,以及其他常用功能,废话不多说,直接上效果图:
代码实现
效果图如上,接下来实现代码:
使用时,如果想实现回显效果node-key必须要传!!!
HTMl:
{{ data[props.label] }}
({{ data[props.children].length }})
JS:
export default {
props: {
value: {
type: undefined,
default: null,
},
data: {
type: Array,
default: null,
},
props: {
type: Object,
default: null,
},
},
data() {
return {
defaultExpandedKeys: [],
};
},
created() {
this.propsInit();
},
mounted() {
setTimeout(this.initData, 10);
},
beforeUpdate() {
this.propsInit();
this.initData();
},
methods: {
initData() {
if (this.$attrs['show-checkbox'] === undefined) {
let newItem = this.recurrenceQuery(this.data, this.props.value, this.value);
if (newItem.length) {
if (this.props.value && newItem[0][this.props.value]) {
this.defaultExpandedKeys = [newItem[0][this.props.value]];
}
this.$nextTick(() => {
this.$refs.myTree.setCurrentNode(newItem[0]);
});
}
} else {
let newValue = JSON.parse(JSON.stringify(this.value));
if (!(newValue instanceof Array)) {
newValue = [newValue];
}
if (newValue?.length) {
let checkList = newValue.map(key => {
if (key) {
let newItem = this.recurrenceQuery(this.data, this.props.value, key);
return newItem[0] || '';
}
});
if (checkList?.length) {
let defaultExpandedKeys = checkList.map(item => item?.[this.props.value || '']);
if (defaultExpandedKeys.length) this.defaultExpandedKeys = defaultExpandedKeys;
this.$nextTick(() => {
this.$refs.myTree.setCheckedNodes(checkList);
});
}
}
}
this.$forceUpdate();
},
// 多选
handleCheckChange(data, e, ev) {
let checkList = this.$refs.myTree.getCheckedNodes();
let setList = null;
if (checkList.length) {
setList = checkList.map(item => item[this.props.value]);
}
this.$emit('input', setList);
// 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点本身是否被选中、节点的子树中是否有被选中的节点
this.$emit('change', data, e, ev);
},
// 单选事件
handleNodeClick(data, e) {
if (!(this.$attrs['select-last-node'] === undefined)) {
if (data[this.props.children] && data[this.props.children]?.length) {
return false;
}
}
if (this.$attrs['show-checkbox'] === undefined) {
this.$emit('input', data[this.props.value]);
this.$refs.mySelect.blur();
}
this.$emit('change', data, e);
},
// 递归查找通用方法
recurrenceQuery(list, key, value) {
if (!list || !key || !value) return [];
let queryData = [];
list.map(item => {
if (item[this.props.children] && item[this.props.children].length) {
queryData.push(...this.recurrenceQuery(item[this.props.children], key, value));
}
if (item[key] == value) {
queryData.push(item);
}
return item;
});
return queryData;
},
selectChange(e) {
if (this.$attrs['show-checkbox'] !== undefined) {
let checkList = e.map(key => {
let newItem = this.recurrenceQuery(this.data, this.props.label, key);
return newItem[0] || '';
});
this.$refs.myTree.setCheckedNodes(checkList);
this.$emit('input', e);
}
},
selectClear(flag) {
if (this.$attrs['show-checkbox'] === undefined) {
if (!flag) this.$emit('input', '');
this.$refs.myTree.setCurrentKey(null);
} else {
if (!flag) this.$emit('input', []);
this.$refs.myTree.setCheckedKeys([]);
}
this.remoteMethod('');
},
getCheckedNodes() {
if (this.value !== null && this.value !== undefined && this.value !== '') {
return this.$refs.myTree.getCheckedNodes();
}
return [];
},
getCurrentNode() {
if (this.value !== null && this.value !== undefined && this.value !== '') {
return this.$refs.myTree.getCurrentNode();
}
return null;
},
valueFilter(val) {
if (this.$attrs['show-checkbox'] === undefined) {
let res = '';
[res] = this.recurrenceQuery(this.data, this.props.value, val);
return res?.[this.props.label] || '';
} else {
if (!val?.length) return [];
let res = val.map(item => {
let [newItem] = this.recurrenceQuery(this.data, this.props.value, item);
return newItem?.[this.props.label] || '';
});
if (!res?.length) return [];
res = res.filter(item => item);
return res;
}
},
propsInit() {
this.props.label = this.props.label || 'label';
this.props.value = this.props.value || 'value';
this.props.children = this.props.children || 'children';
if (this.$attrs['select-last-node'] !== undefined && !this.props.disabled) {
this.props.disabled = data => data?.[this.props.children]?.length;
this.$attrs['check-strictly'] = true;
}
},
remoteMethod(query) {
this.$refs.myTree.filter(query);
},
filterNode(value, data) {
if (!value) return true;
return data[this.props.label].indexOf(value) !== -1;
},
},
watch: {
value: {
deep: true,
handler(val) {
if (!val || !val?.length) {
this.selectClear(true);
}
},
},
},
};
CSS:
.selecTree {
max-height: 50vh;
overflow: auto;
padding: 5px;
}
.el-select {
width: 100%;
}
.slotSpan {
font-size: 14px;
b {
font-weight: normal;
font-size: 12px;
color: #999;
}
}
.selecTree ::v-deep .el-tree-node__content {
font-size: 14px;
}