可以實現多選,聯想搜索(僅單選支持)
功能展示
可聯想搜索的單選

多選

使用介紹
支持從父組件傳的參數有
'redBorder','width','height','placeholder','optionList','selectOption','multiple','color','conflictList','disabled','isSearch'——
按照自己需要傳入,不需要的可不傳
redBorder: 邊框是否變紅(自己項目中做必填校驗時需要,可忽略不傳)——可傳值 true/false
width: 文本框的長度(默認208px)——傳入值示例 width="100px"
height: 文本框的高度(默認28px)——傳入值示例 height="30px"
placeholder:文本框提示語(默認請選擇)
optionList:下拉選擇列表——傳入值示例([{name: '下拉選項1',code: 1}])
selectOption: 默認選中項 ——傳入值示例(單選 直接傳選中項code :如1,多選則需要傳選中的數組[{name: '下拉選項1',code: 1}])
multiple:是否多選——多選傳true,單選傳false或不傳
color:文本框中文字顏色—— 傳定義了顏色的類名
disabled:是否禁用——true/false
conflictList: 在項目中用來檢查沖突時使用可忽略不傳
isSearch: 是否支持聯想搜索——true/false
觸發到父組件可接收的方法
@input:聯想搜索時input框輸入時觸發,可用來重新請求下拉列表
@change: 選中項發生改變時觸發,可用來給選中項賦值
@visibleChange: 下拉列表收起/展開時觸發 參數為true時表示展開,false表示收起(可實現點擊下拉框實時獲取下拉列表數據)
調用組件
// 引入組件 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); },
組件源碼如下
注:由於字體顏色、字體大小、背景顏色、邊框顏色、常用flex布局是直接寫的公共樣式庫中的類名,故需樣式需自己調整
<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>
