行业知识
Element树型下拉框/vue2树型下拉框/TreeSelect/树型下拉
2026-11-13 18:24:43
来源:互联网转载
前言
今天小谭要给大家分享的是基于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;}