最近公司做项目碰到个需求,要实现一个二级下拉的多选框,并且实现选中一级条目时,此条目下的二级条目全选和全不选的功能。全选和全不选倒简单通过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样式的美化,二级多选框的数据结构定义是一颗树,可在组件初始化时,通过入参传进去。