0


Element树型下拉框/vue2树型下拉框/TreeSelect/树型下拉

前言

    今天小谭要给大家分享的是基于element ui 的下拉框和树型控件二次分装的树型下拉框,element plus新增了这一组件,但是对于还在使用vue2的我来说,就很不友好。组件可以实现单选和多选,以及其他常用功能,废话不多说,直接上效果图:


代码实现

效果图如上,接下来实现代码:

使用时,如果想实现回显效果node-key必须要传!!!

HTMl:

<!-- 
 * @description: 通用树型下拉框
 * @fileName: treeSelect.vue 
 * @author: tan
 * @date: 2023-03-07 17:15:03
 * @Attributes: data    展示数据    array
                props    配置选项,具体配置可以参照element ui库中el-tree的配置    object
                show-checkbox    节点是否可被选择    boolean
                check-strictly    在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false    boolean
                icon-class    自定义树节点的图标    string
                load    加载子树数据的方法,仅当 lazy 属性为true 时生效    function(node, resolve)
                lazy    是否懒加载子节点,需与 load 方法结合使用    boolean
                disabled    下拉框是否禁用
                getCheckedKeys    若节点可被选择(即 show-checkbox 为 true),则返回目前被选中的节点的 key 所组成的数组
                getCurrentNode    获取当前被选中节点的 data,若没有节点被选中则返回 null  
                collapse-tags    多选时是否将选中值按文字的形式展示
                select-last-node    单选时是否只能选择最后一个节点
                Scoped Slot 自定义树节点的内容,参数为 { node, data }
                show-count 若节点中存在children 则在父节点展示所属children的数量,注意但设置插槽时 show-count将失效!
                clearable    单选时是否可以清空选项
                !!!!!必传!!!!!! node-key    每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 !!!!!!
!-->

<template>
   <el-select
      :value="value"
      :placeholder="$attrs['placeholder']"
      :multiple="$attrs['show-checkbox']"
      :disabled="$attrs['disabled']"
      :clearable="$attrs['show-checkbox']==undefined?$attrs['clearable']:false"
      :collapse-tags="$attrs['collapse-tags']"
      @change="selectChange"
      @clear="selectClear"
      ref="mySelect"
   >
      <template slot="empty">
         <div class="selecTree">
            <el-tree
               :data="data"
               :props="props"
               @node-click="handleNodeClick"
               :show-checkbox="$attrs['show-checkbox']"
               :check-strictly="$attrs['check-strictly']"
               :icon-class="$attrs['icon-class']"
               :lazy="$attrs['lazy']"
               :load="$attrs['load']"
               :node-key="$attrs['node-key']"
               @check-change="handleCheckChange"
               :default-expanded-keys="defaultExpandedKeys"
               ref="myTree"
            >
               <template slot-scope="{ node, data }">
                  <slot :node="node" :data="data">
                     <span class="slotSpan">
                        <span>
                           {{ data[props.label||'label'] }}
                           <b
                              v-if="$attrs['show-count']!=undefined&&data[props.children || 'children']"
                           >({{data[props.children || 'children'].length}})</b>
                        </span>
                     </span>
                  </slot>
               </template>
            </el-tree>
         </div>
      </template>
   </el-select>
</template>

JS:

export default {
    props: {
        value: {
            type: undefined,
            default: null,
        },
        data: {
            type: Array,
            default: null,
        },
        props: {
            type: Object,
            default: null,
        },
    },
    data() {
        return {
            defaultExpandedKeys: [],
        };
    },
    mounted() {
        setTimeout(this.initData, 2000);
    },
    beforeUpdate() {
        this.initData();
    },
    methods: {
        initData() {
            if (this.$attrs['show-checkbox'] === undefined) {
                let newItem = this.recurrenceQuery(this.data, this.props.label, this.value);
                if (newItem.length) {
                    if (this.$attrs['node-key'] && newItem[0][this.$attrs['node-key']]) {
                        this.defaultExpandedKeys = [newItem[0][this.$attrs['node-key']]];
                    }
                    this.$refs.myTree.setCurrentNode(newItem[0]);
                }
            } else {
                let newValue = JSON.parse(JSON.stringify(this.value));
                if (!(newValue instanceof Array)) {
                    newValue = [newValue];
                }
                if (newValue[0]) {
                    let checkList = newValue.map(key => {
                        if (key) {
                            let newItem = this.recurrenceQuery(this.data, this.props.label, key);
                            return newItem[0] || '';
                        }
                    });
                    if (checkList[0]) {
                        if (this.$attrs['node-key']) {
                            let defaultExpandedKeys = checkList.map(item => item[this.$attrs['node-key'] || '']);
                            if (defaultExpandedKeys.length) this.defaultExpandedKeys = defaultExpandedKeys;
                        }
                        this.$refs.myTree.setCheckedNodes(checkList);
                    }
                }
            }
        },
        // 多选
        handleCheckChange(data, e, ev) {
            let checkList = this.$refs.myTree.getCheckedNodes();
            let setList = null;
            if (checkList.length) {
                setList = checkList.map(item => item[this.props.label]);
            }
            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 || 'children'] && data[this.props.children || 'children'][0]) {
                    return false;
                }
            }
            if (this.$attrs['show-checkbox'] === undefined) {
                this.$emit('input', data[this.props.label]);
                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 || 'children'] && item[this.props.children || 'children'].length) {
                    queryData.push(...this.recurrenceQuery(item[this.props.children || '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() {
            this.$emit('input', null);
        },
        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;
        },
    },
};

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;
}

本文转载自: https://blog.csdn.net/qq_45947497/article/details/129400063
版权归原作者 小谭鸡米花 所有, 如有侵权,请联系我们删除。

“Element树型下拉框/vue2树型下拉框/TreeSelect/树型下拉”的评论:

还没有评论