一、前言
在自定义多选可搜索下拉框的时候,当搜索无匹配数据的时候,下拉框内自定义的搜索框等元素都会消失,该组件完美地解决了这个问题!特此记录一下。
二、实现效果
- 选择下拉框打开时可自动聚焦到input输入框;
- 点击全选可选择全部item;
- 可清空已选择项;
- 已选择项在input框里呈同一行可滑动显示;
- 可选项过多时搜索框不会跟随着滚动,固定搜索框。
实现效果如下:
三、代码实现
1、创建组件
在父组件Demos创建一个MultipleSelect子组件,如下:
2、MultipleSelect子组件代码
<template>
<el-select
multiple
v-model="selectNameArr"
placeholder="请选择"
clearable
:style="{'width':width}"
@focus="autoFocusInput('search_input1')"
@change="changeSelectBrand"
@remove-tag="removeTag"
popper-class="select-multiple">
<!-- 当下拉框搜索为空时展现的内容 -->
<template slot="empty">
<el-row style="padding:6px 10px 0" v-if="!inputVisible">
<el-col :span="18">
<span>选择收件人:</span>
<el-input class="search_input" size="mini" style="width:calc(100% - 100px)" v-model="searchValue" placeholder="请输入关键字搜索" clearable @input="searchUser"></el-input>
</el-col>
<el-col :span="6">
<el-button type="primary" size="mini" @click.native="selectAll()">全选</el-button>
<el-button type="warning" size="mini" @click.native="clearAll()">清空</el-button>
</el-col>
</el-row>
<el-divider class="row_divider"></el-divider>
<div class="el-select-dropdown__empty">无匹配数据</div>
</template>
<!-- 当下拉框不为空时展现的内容 -->
<div class="select-box">
<el-row type="flex" justify="center" style="padding:0 10px" v-if="inputVisible">
<el-col :span="18">
<span>选择收件人:</span>
<el-input class="search_input1" size="mini" style="width:calc(100% - 100px)" v-model="searchValue" placeholder="请输入关键字搜索" clearable @input="searchUser"></el-input>
</el-col>
<el-col :span="6">
<el-button type="primary" size="mini" @click.native="selectAll()">全选</el-button>
<el-button type="warning" size="mini" @click.native="clearAll()">清空</el-button>
</el-col>
</el-row>
<el-divider class="row_divider"></el-divider>
<div class="select-content" v-if="!loading">
<span v-for="item in receiverNameOptModel" :key="item.id">
<el-tooltip effect="dark" :open-delay="500" :content="item.name+' '+item.name_en" placement="top">
<el-option :label="item.name+' '+item.name_en" :value="item.name+' '+item.name_en"></el-option>
</el-tooltip>
</span>
</div>
</div>
</el-select>
</template>
<script>
export default {
name: 'MultipleSelect',
props:{
receiverNameOpt: { //接受的数据为[{id:1,name:'张三',name_en:'zhangsan',...},...]格式
type: Array,
default: ()=>[]
},
width:{ //传入宽度值为字符串形式,如'50%'
type: String,
default:'100%',
}
},
data(){
return{
searchValue: '',
selectNameArr: [],
receiverNameOptModel: [],
loading: false,
inputVisible: false,
}
},
mounted(){
this.$bus.$on('clearReciever',this.clearAll)
},
watch:{
receiverNameOpt:{
immediate:true,
handler(val){
if(val.length === 0){
this.loading = true
}else{
this.loading = false
}
this.receiverNameOptModel = JSON.parse(JSON.stringify(this.receiverNameOpt))
}
},
receiverNameOptModel:{
immediate:true,
handler(val){
if(val.length === 0){
this.inputVisible = false
this.autoFocusInput("search_input")
}else{
this.inputVisible = true
this.autoFocusInput("search_input1")
}
}
},
},
methods:{
// 全选全部品类
selectAll() {
this.selectNameArr = this.receiverNameOpt.map(p=>p.name+' '+p.name_en)
let ret =[]
ret = this.receiverNameOptModel.filter(p=>{ return this.selectNameArr.includes(p.name+p.name_en) })
this.$emit('getmultipleReceiver',ret)
},
// input自动聚焦
autoFocusInput(classname) {
this.$nextTick(() => {
let dom = document.getElementsByClassName(classname)[0];
if(dom) setTimeout(()=>{ dom.children[0].focus() },200)
});
},
// 选择收件人
changeSelectBrand(val) {
let ret =[]
ret = this.receiverNameOptModel.filter(p=>{return val.includes(p.name+p.name_en)})
this.$emit('getmultipleReceiver',ret)
},
removeTag(val) {
for(let i=0;i<this.selectNameArr.length;i++){
if(this.selectNameArr[i] === val) this.selectNameArr.splice(index,1)
}
},
// 清空已选择的收件人
clearAll() {
this.selectNameArr.splice(0,this.selectNameArr.length)
this.searchValue = ''
this.receiverNameOptModel = JSON.parse(JSON.stringify(this.receiverNameOpt))
},
// 搜索用户收件人
searchUser(query) {
if (query !== '') {
this.receiverNameOptModel = this.receiverNameOpt.filter((p)=>{
return p.name.toLocaleLowerCase().includes(query.toLocaleLowerCase()) || p.name_en.toLocaleLowerCase().includes(query.toLocaleLowerCase())
})
} else {
this.receiverNameOptModel = JSON.parse(JSON.stringify(this.receiverNameOpt))
}
},
}
}
</script>
<style>
.select-multiple.is-multiple{
width: 50%;
}
</style>
<style scoped>
.select-multiple .select-content {
height: max-content;
height: -webkit-max-content;
height: -moz-max-content;
max-height: 200px;
overflow: hidden;
overflow-y: auto;
}
.select-multiple .select-content::-webkit-scrollbar{
width: 2px!important;
}
.select-multiple .el-select-dropdown__item {
width: 33%;
height: 26px;
line-height: 26px;
margin-right: 1px;
padding: 0 10px;
display: inline-block;
border-bottom: 1px solid #cccccc40;
border-right: 1px solid #cccccc40;
box-shadow: 1px 1px 4px #e4e4e4;
}
.select-multiple .el-select-dropdown__item.selected:hover,
.select-multiple .el-select-dropdown__item:hover{
color: #fff;
background-color: #409EFF;
}
::v-deep .el-select__tags-text {
display: inline-block;
max-width: 80px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.is-multiple .select-content ::v-deep .el-select-dropdown__item.selected::after{
right: 2px!important;
}
::v-deep .el-select__tags {
flex-wrap: nowrap;
overflow-x: auto;
margin-left: 3px;
}
::v-deep .el-select__tags::-webkit-scrollbar{
height: 2px;
border-radius: 1px;
background-color: #e4e4e4;
}
.row_divider{
margin: 6px 0;
}
</style>
3、Demos父组件调用MultipleSelect子组件
<template>
<!-- 省略... -->
<el-tab-pane label="自定义select下拉框" name="third">
<MultipleSelect :width="'50%'" :receiverNameOpt="multipleSelectDataList"></MultipleSelect>
</el-tab-pane>
<!-- 省略... -->
</template>
<script>
import MultipleSelect from "./MultipleSelect";
export default {
name:"Demos",
components:{ MultipleSelect },
data() {
return {
multipleSelectDataList:[
{
id:1,
name:'张三',
name_en:'zhangsan',
},
{
id:2,
name:'李四',
name_en:'lisi',
},
{
id:3,
name:'王五',
name_en:'wangwu',
},
{
id:4,
name:'赵六',
name_en:'zhaoliu',
},
//省略...
],
}
}
}
</script>
四、总结
此篇文章的重点就在于搜索无匹配数据时搜索框消失的情况,还有两个搜索inpu框实时切换自动聚焦的问题。共勉^o^