vue项目中基于element-ui的Tree和Select进行二次封装

2,305 阅读2分钟

在一次项目开发过程中,需要用到类似于级联选择器(Cascader)的组件,但是级联选择器是横向排列,ui给的样式是竖向排列的(如下图),于是动手用element的Tree和Select组件进行了二次封装,实现了如下功能支持单选和多选的树形选择

image.png

实现代码:

<div class="my-select">
    <el-select :value="value" :multiple="multiple" placeholder="请选择" @remove-tag="removeTag"
               :clearable="clearable" @clear="clearHandle">
        <el-option :value="value">
            <el-tree
              id="tree-option"
              ref="selectTree"
              :accordion="accordion"
              :data="treeData"
              :props="defaultProps"
              show-checkbox
              :expand-on-click-node="false"
              :node-key="defaultProps.value"
              :check-strictly="true"
              @check="handleNodeClick"
              @check-change="handleCheckChange"
            ></el-tree>
        </el-option>
    </el-select>
</div>
//样式修改
.my-select {
    //display: flex;
    //flex-direction: column;
    //align-items: center;
}

.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
    height: auto;
    padding: 0;
    overflow: hidden;
    overflow-y: auto;
}

.el-select-dropdown__item.selected {
    font-weight: normal;
}

ul li >>> .el-tree .el-tree-node__content {
    height: auto;
    padding: 0 20px;
}

.el-tree-node__label {
    font-weight: normal;
}

.el-tree >>> .is-current .el-tree-node__label {
    color: #409eff;
    font-weight: 700;
}

.el-tree >>> .is-current .el-tree-node__children .el-tree-node__label {
    color: #606266;
    font-weight: normal;
}

/deep/ .el-select {
    width: 100% !important;
}

实现具体的方法:定义props,接受从父组件传递过来的参数

props: {
    /*配置选项*/
    defaultProps: {
        type: Object,
        default: () => {
            return {
                value: "id", // ID字段名
                label: "label", // 显示名称
                children: 'children' // 子级字段名
            }
        }
    },
    /*展示数据*/
    treeData: {
        type: Array,
        default: () => []
    },
    /* 可清空选项 */
    clearable: {
        type: Boolean,
        default: () => true
    },
    /* 自动收起 */
    accordion: {
        type: Boolean,
        default: () => true
    },
    /*单选初始值*/
    radioValue: {
        type: String,
        default: () => ''
    },
    /*多选初始值*/
    multipleValues: {
        type: Array,
        default: () => []
    },
    /*是否多选*/
    multiple: {
        type: Boolean,
        default: () => true
    }
}

初始化加载组件时,判断是多选还是单选

mounted() {
    // 父组件传递的multiple值为true,则是单选组件,反之为多选,调用对应的方法,初始化默认数据
    this.multiple ? this.radioInit() : this.multipleInit();
}

接下来实现对应的方法:初始化默认值

// 初始化多选默认值,如果有传递默认值,则回显默认值
multipleInit() {
    // 如果有传默认值过来,则渲染到组件中
    if (this.multipleValues.length > 0) {
        this.$refs.selectTree.setCheckedKeys(this.multipleValues);
        this.selectedNodes = this.$refs.selectTree.getCheckedNodes();
        this.value = this.selectedNodes.map(item => item[this.defaultProps.label]);
    }
},
// 初始化单选默认值
radioInit() {
    if (this.radioValue) {
        this.$refs.selectTree.setCheckedKeys([this.radioValue]);
        this.selectedNodes = this.$refs.selectTree.getCheckedNodes();
        this.value = this.selectedNodes[0][this.defaultProps.label];
    }
}

切换选项的方法

handleNodeClick(node, el) {
    this.selectedNodes = el.checkedNodes;
    if (this.multiple) {
        // 多选
        this.value = el.checkedNodes.map(item => item[this.defaultProps.label]);
    } else {
        // 单选
        this.value = el.checkedNodes[0][this.defaultProps.label];
    }
}

移除选项

// 移除选项(单项移除)
removeTag(tag) {
    let arr = this.selectedNodes.filter(item => item[this.defaultProps.label] === tag);
    this.$refs.selectTree.setChecked(arr[0].id, false);
    this.value.splice(this.value.indexOf(tag), 1);
},
// 清除选中项(清除所有)
clearHandle() {
    if (this.multiple) {
        this.value = [];
    } else {
        this.value = '';
    }
    this.$refs.selectTree.setCheckedKeys([]);
}
// 获取选中id值,通过$emit将此事件弹射出去给父组件,获取选中的对应id值
getCheckedKeys() {
    return this.$refs.selectTree.getCheckedKeys()
},
// 节点状态发生变化时的回调,针对单选做特殊处理
handleCheckChange(data, checked) {
    if (!this.multiple && checked === true) {
        // 单选
        this.$refs.selectTree.setCheckedNodes([data]);
    }
}

源码地址:Github