element-ui实现二级多选框


最近公司做项目碰到个需求,要实现一个二级下拉的多选框,并且实现选中一级条目时,此条目下的二级条目全选和全不选的功能。全选和全不选倒简单通过JS实现一下就行了,最主要的是elementUI没有现成的二级多选下拉框,因此首先需要实现一个多选二级下拉框。经过多方查阅资料,终于找到了elementUI有一个el-pot-right的class样式。这个样式可以实现在某个选项后面出现二级面板。在实现过程费了不少劲,故在此记录一下

Select 选择器

在做之前我在CSDN找了一下,发现基本都是两个下拉框然后实现二级联动,类似第一个框选择省份,第二个框自动出现该省份下对应的所有城市。比如下面这样的

而我实际上想要这样的效果(下面这图是我已经做好的)

话不多说直接上代码吧,这里用到了select框的multiple和collapse-tags两个属性,multiple是实现下拉框可多选,collapse-tags是实现当多选时,只展示一个条目多余的显示数字累加。同时我把el-select套了一层封装自定义组件,并通过v-model可以直接获取到选择的值,这里就涉及到vue组件的一个高级用法了,自定义组件怎么绑定v-model。一般父子组件中,当子组件中的一些input框,select框值发生改变,向父组件返回这些改变的值是是通过监听函数的方式,而如果仅仅只是返回一个object时,用v-model更加方便。话不多说,直接上代码吧

定义MySelect组件

<template>
    <div>
      <el-select v-model="selectData" multiple collapse-tags placeholder="请选择" class="select-item" @change="changeData">
        <el-option v-for="item1 in treeData"
                   :key="item1.value"
                   :label="item1.label"
                   :value="item1.value">
          <span>{{item1.label}}</span>
          <div class="el-pot-right">
            <el-option v-for="item2 in item1.children"
                       :key="item2.value"
                       :label="item2.label"
                       :value="item2.value">
              <span>{{item2.label}}</span>
            </el-option>
          </div>
        </el-option>
      </el-select>
    </div>
</template>
<script>
    export default {
        name:'my-select',
        model: {
            prop: 'data',
            event: 'revert'
        },
        props: {
            treeData:{
                type: Array,
                default () {
                    return []
                }
            }
        },
        data() {
            return {
                selectData:[]
            }
        },
        methods:{
            changeData(){
                this.$emit('revert',this.selectData)
            }
        }
    }
</script>
<style>
  .el-pot-right{
    position: absolute;
    top:0;
    right: -105%;
    width: 100%;
    display: none;
    background-color: #FFF;
    border: 1px solid #E4E7ED;
    box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
    box-sizing: border-box;
    border-radius: 4px;
    padding: 5px 0;
  }
  .is-multiple .el-scrollbar{
    overflow: initial;
  }
  .is-multiple .el-scrollbar__wrap{
    overflow: initial;
    margin-right:0 !important;
    margin-bottom: 0 !important;
  }
  .is-multiple .el-select-dropdown__item{
    overflow: initial;
  }
  .is-multiple .el-select-dropdown__item>.el-pot-right:hover{
    display: inline-block;
  }
  .is-multiple .el-select-dropdown__item.hover>.el-pot-right{
    display: inline-block;
  }
  .is-multiple .el-scrollbar__bar{
    display: none !important;
    opacity:0 !important;
  }

</style>

引用MySelect组件

在表单或是div中引用MySelect组件

 <template>
    <div>
         <el-col :span="11">
            <my-select :tree-data="treeData" v-model="treeDataList"></my-select>
          </el-col>
          <el-col :span="11">
            <el-button @click="getSelectData">取值</el-button>
          </el-col>
     </div>
 </template>

 <script type="text/ecmascript-6">
  import MySelect from '../sub/MySelect.vue'

    export default {
        components: {
            MySelect
        },
        data() {
            return {
                treeDataList:[],
                treeData:[
                    {
                        label:"熟食类",
                        value:"cooked",
                        children:[
                            {
                                label:"炸鸡腿",
                                value:"drumstick"
                            },
                            {
                                label:"辣条",
                                value:"strips"
                            },
                            {
                                label:"小鱼干",
                                value:"fillet"
                            },
                            {
                                label:"老干妈",
                                value:"old"
                            },
                            {
                                label:"烤面包",
                                value:"bao"
                            }
                        ]
                    },
                    {
                        label:"炒货类",
                        value:"mast",
                        children:[
                            {
                                label:"杏仁",
                                value:"almond"
                            },
                            {
                                label:"腰果",
                                value:"cashew"
                            },
                            {
                                label:"夏威夷果",
                                value:"macadamia"
                            },
                            {
                                label:"开心果",
                                value:"pistachio"
                            },
                            {
                                label:"核桃",
                                value:"walnut"
                            }
                        ]
                    },
                    {
                        label:"水果类",
                        value:"fruit",
                        children:[
                            {
                                label:"苹果",
                                value:"apple"
                            },
                            {
                                label:"香蕉",
                                value:"banana"
                            },
                            {
                                label:"菠萝",
                                value:"pineapple"
                            },
                            {
                                label:"草莓",
                                value:"strawberry"
                            }
                        ]
                    }
                ]
            }
        },
        methods: {
            getSelectData(){
                console.log('--------------------');
                console.log(this.treeDataList);
            }
        }
    }

大功告成,比较难的就是自定义组件的v-model用法,剩下的就是一些css样式的美化,二级多选框的数据结构定义是一颗树,可在组件初始化时,通过入参传进去。


Author: 顺坚
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 顺坚 !
评论
 Previous
vue和react实现组织架构树 vue和react实现组织架构树
公司项目需求,要在页面中实现一个公司组织架构图,并实现每个节点可以通过点击事件增加子节点,删除子节点。当时首先想到的是用echart的树图实现,但是echart的树图的节点不能自定义样式,而且点击事件也不是那么方便,于是就放弃了。然后在gi
2020-04-01
Next 
python基本概念和语法 python基本概念和语法
随着人工智能的发展,python语言也越来越受到青睐。逐渐成为了人工智能领域的首选编程语言,实际上python不仅在人工智能领域应用广泛,同样可以用于服务端开发(虽然服务端是Java的主场)。目前Python是排名前3的最受欢迎和增长最快的
2020-03-28
  TOC