可以实现多选,联想搜索(仅单选支持)
功能展示
可联想搜索的单选
多选
使用介绍
支持从父组件传的参数有
// 引入组件 import selectOption from "../../../basic/selectOption"; components: { selectOption }, // 使用 <selectOption :selectOption="role.code" :optionList="roleOption" placeholder="请选择角色" @change="selectRole" ></selectOption> // data中的变量 role:{name: ‘‘,code: ‘‘} optionList: [{name: ‘角色1‘,code: ‘1‘}] // methods中的方法 // 点击选择某个角色时触发 selectRole(val) { this.$set(this.role, "name", val.name); this.$set(this.role, "code", val.code); },
<template> <div> <el-popover placement="bottom-start" :visible-arrow="false" :popper-class="$store.state.model == 1 ? ‘popperTop0‘ : ‘popperTop0 simpleStyle‘" v-model="optionShow" :disabled="disabled" trigger="click"> <div class="selectBox rowJbAc" slot="reference" :class="[optionShow ? ‘borderMcA1‘ : ‘borderScA9‘,redBorder? ‘redBorder‘: ‘‘]" :style="{width: selectWidth,minHeight: selectHeight}"> <!-- 复选且不为空时展示 --> <div class=" multipleTextBox fontScA2 fontSizeA flexRow" v-if="multiple && selectedOptions.length!=0" :class="[disabled ? ‘notAllow‘ : ‘pointer‘]"> <!-- <div v-for="(item,index) in selectedOptions" :class="[isConflict(2,item.code) ? ‘fontScC2‘ : ‘fontScA2‘]" :key="index">{{item.name}}</div> --> <div v-for="(item,index) in selectedOptions" :key="index" class="rowAc multipleTextItem borderScN4 borderAll"> <div class="fontSizeA multipleText" :class="[isConflict(2,item.code) ? ‘fontScC2‘ : ‘fontScA2‘]">{{item.name}}</div> <div class="icon-close-circle fontSizeA fontScN6 pointer" @click.stop="clearItem(index)"></div> </div> <!-- <input type="text" class="selectSearchInput fontSizeB fontScN8" v-model="selectText" @input="inputEvent"> --> </div> <!-- 复选展示 --> <input type="text" @focus="inputFocus" ref="input" v-if="multiple &&selectedOptions.length==0" v-model="selectText" readonly class="input fontSizeA" :class="{‘fontScA1‘: !color || color==‘fontScA2‘ ,‘fontScC2‘: color == ‘fontScC2‘,‘opacity‘:multiple&&selectedOptions.length!=0,‘notAllow‘:disabled }" :placeholder="selectPlaceholder"> <!-- 单选展示 --> <input type="text" ref="input" v-if="!multiple" @focus="inputFocus" @blur="inputBlur" v-model="selectText" :readonly="!isSearch" class="input fontSizeA" :class="[color? color: ‘fontScA2‘,disabled ? ‘notAllow‘ : ‘pointer‘]" :placeholder="selectPlaceholder" @input="inputEvent"> <div class="fontSizeB fontScN5 arrowIcon rowAc" :class="[optionShow ? ‘icon-arrow-up‘ : ‘icon-arrow-down‘,disabled ? ‘notAllow‘ : ‘pointer‘]"></div> </div> <div class="optionWrap fontSizeA bgcScB1" :style="{minWidth: selectWidth}"> <div class="optionItem hoverBgcScA10 rowJbAc textOver" v-for="(item,index) in optionList" :key="index" :class="[checkSelected(item) ? ‘fontMcA1‘ : ‘fontScA2‘]" @click.stop="clickOption(item)" ref="selectInput"> <!-- <input type="text" class="selectInputOpacity"> --> {{item.name}} </div> <div v-if="optionList.length == 0" class="fontScA6 fontSizeA empty" >暂无数据</div> </div> </el-popover> </div> </template> <script> export default { data() { return { selectWidth: ‘208px‘, // 选择框宽度 selectHeight: ‘28px‘, // 选择框高度 selectPlaceholder: ‘请选择‘, // 提示消息 selectText: ‘‘, selectedOption: {name: ‘‘,code: ‘‘},// 记录当前选中的项————单选 selectedOptions: [],// 记录当前选中的项————多选 optionShow: false,// 选择框是否展示 optionClick: false,// 是否点击选项 isGetDefault: false, // 是否赋值默认数据 oldSelectText: ‘‘, // 记录旧的输入值 } }, watch: { optionList(newValue) { // console.log(‘下拉列表:‘,newValue) this.setOption(‘listChange‘) }, selectOption() { this.setOption(‘‘) }, optionShow() { this.$emit(‘visibleChange‘,this.optionShow) if(this.optionShow) { // 滚动到对应的位置 // this.$refs.input.focus() if(!this.multiple && this.selectedOption.name) { setTimeout(()=>{ var idx = this.optionList.findIndex(item =>{return item.code == this.selectedOption.code}) if(idx != -1 && this.$refs.selectInput && this.$refs.selectInput[idx]) { // this.$refs.selectInput[idx].focus() this.$refs.selectInput[idx].scrollIntoView() } },20) } }else { if(this.isSearch && this.$refs.input) { this.$refs.input.blur() } } }, }, created() { this.$bus.$on(‘changeSelect‘) }, // width ————宽度 // placeholder———— 提示 // optionList————选项列表{name: ‘‘,code: ‘‘} // selectOption————选中项 props: [‘redBorder‘,‘width‘,‘height‘,‘placeholder‘,‘optionList‘,‘selectOption‘,‘multiple‘,‘color‘,‘conflictList‘,‘disabled‘,‘isSearch‘], mounted() { this.setOption(‘‘) }, methods: { inputFocus() { }, // input框失焦 inputBlur() { this.selectText = this.selectedOption.name this.optionShow = false }, // 点击选项选中 clickOption(item) { // console.log(‘clickOption‘) this.optionClick = true if(this.multiple) { // 多选 var idx = this.selectedOptions.findIndex(option => {return option.code == item.code}) if(idx == -1) { this.selectedOptions.push(item) }else { this.selectedOptions.splice(idx,1) } // this.selectedOptions.forEach((option,index) => { // if(index == 0) { // this.selectText = option.name // }else { // this.selectText += `,${option.name}` // } // }) this.$emit(‘change‘,this.selectedOptions) }else { // 单选 this.optionShow = false this.selectText = item.name this.$set(this.selectedOption,‘name‘,item.name) this.$set(this.selectedOption,‘code‘,item.code) this.$emit(‘change‘,this.selectedOption) } }, checkSelected(item) { if(this.multiple) { // 多选 return this.selectedOptions.some((option) => {return item.code == option.code}) }else { // 单选 return item.code === this.selectedOption.code } }, // 检查是否冲突 isConflict(type,id) { if(!this.conflictList) { return false } return this.conflictList.some( item => { return item.type == type && item.id ==id }) }, // 赋值 setOption(type) { // 判断父页面有无传对应的值 if(this.width) { this.selectWidth = this.width } if(this.height) { this.selectHeight = this.height } if(this.placeholder) { this.selectPlaceholder = this.placeholder } // 有选中项 if(type != ‘listChange‘ || !this.isGetDefault) { if(this.selectOption && this.selectOption != ‘‘) { if(this.multiple) { // 多选 this.selectedOptions = [] this.selectOption.forEach((item,index) => { // if(index == 0) { // this.selectText = item.name // }else { // this.selectText += `,${item.name}` // } var idx = this.optionList.findIndex(option => {return option.code == item.code}) if(idx != -1) { this.selectedOptions.push(this.optionList[idx]) } }) }else { // 单选 var idx = this.optionList.findIndex(item => {return item.code == this.selectOption }) if(idx != -1) { this.selectText = this.optionList[idx].name this.$set(this.selectedOption,‘name‘,this.optionList[idx].name) this.$set(this.selectedOption,‘code‘,this.optionList[idx].code) } } }else if(this.selectOption === 0) { var idx = this.optionList.findIndex(item => {return item.code == this.selectOption }) if(idx != -1) { this.selectText = this.optionList[idx].name this.$set(this.selectedOption,‘name‘,this.optionList[idx].name) this.$set(this.selectedOption,‘code‘,this.optionList[idx].code) } }else { if(!this.multiple) { this.selectText = ‘‘ this.selectedOption = {name: ‘‘,code: ‘‘} }else { this.selectedOptions = [] } } this.isGetDefault = true } }, inputEvent() { if(this.oldSelectText != this.selectText) { this.oldSelectText = this.selectText this.$emit(‘input‘,this.selectText) } }, // 删除某个多选项 clearItem(index) { console.log(‘sleectOption:‘,index,this.selectOption) this.selectedOptions.splice(index,1) this.$emit(‘change‘,this.selectedOptions) } } } </script> <style lang="scss" scoped> .selectSearchInput { flex: 1; min-width: 80px; border: none; outline: none; } .opacity { opacity: 0; position: absolute; top: 0; left: 0; } .multipleTextBox { flex-wrap: wrap; flex: 1; padding: 0 4px 0 8px; min-height: 26px; } .multipleTextItem { min-height: 20px; line-height: 20px; padding: 0 4px; margin-top: 2px; margin-bottom: 2px; box-sizing: border-box; border-radius: 2px; margin-right: 4px; } .multipleText { margin-right: 2px; } .optionWrap::-webkit-scrollbar{ width:4px; height:4px; } .selectBox { position: relative; border-width: 1px; border-style: solid; border-radius: 4px; box-sizing: border-box; outline: none; .input { min-height: 26px; border-radius: 4px; line-height: 26px; text-indent: 8px; border: none; flex: 1; outline: none; } .arrowIcon { min-height: 26px; height: 100%; padding: 0 10px; } } .empty { height: 28px; line-height: 28px; text-align: center; } .optionWrap { // position: absolute; max-height: 300px; overflow: auto; // top: 28px; // left: 0px; // z-index: 4; // width: 100%; // padding: 2px 12px 12px; box-sizing: border-box; // border-style: solid; // border-width: 1px; border-radius: 4px; } .optionItem { position: relative; padding: 0 8px; box-sizing: border-box; // margin-top: 10px; height: 28px; border-radius: 5px; flex: 1; cursor: pointer; } // .selectInputOpacity { // width: 0px; // height: 0px; // opacity: 0; // position: absolute; // top: 0; // left: 0; // border: none; // outline: none; // } </style>
原文:https://www.cnblogs.com/pyx-blog/p/14814571.html