1、组件封装
<template>
<div class="select-container">
<div class="input-wrapper">
<span class="input-prefix">{{ prefix }}</span>
<input
v-model="selectedValue"
type="text"
class="input"
:placeholder="placeholder"
:readonly="readonly"
@click="handleClick(selectedValue)"
>
<span class="input-suffix">
<i v-if='showOptions' class="iconfont qywx-xiala1"/>
<i v-else class="iconfont qywx-xiala"/>
</span>
</div>
<div
v-if="showOptions"
class="options-container"
>
<ul class="options">
<li
v-for="(option, index) in options"
:key="index"
class="option"
:class="{'active': option[valueProp] === selectedValue, 'disabled': option.isDisabled,'hidden': !option.visible}"
@click="handleSelect(option)"
>
<span> {{ option[labelProp] }}</span>
<span v-if="option[valueProp] === selectedValue">
<i class="iconfont qywx-a-xuanzhonglansexuanzhong"/>
</span>
</li>
<li
v-if="filteredOptions.length === 0 && selectedValue !== ''"
class="option disabled"
>
无搜索结果
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'Select',
props: {
prefix: {
type: String,
default: ''
},
selectedValue: {
type: [String, Number],
default: ''
},
options: {
type: Array,
required: true
},
readonly: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: '请选择'
},
labelProp: {
type: String,
default: 'label'
},
valueProp: {
type: String,
default: 'value'
}
},
model: {
prop: 'selectedValue',
event: 'change'
},
data() {
return {
showOptions: false,
}
},
computed: {
filteredOptions() {
const searchValue = this.selectedValue.trim().toLowerCase();
const labelProp = this.labelProp;
return this.options.map(option => {
option.visible = option[labelProp].toLowerCase().includes(searchValue)
return option;
})
}
},
methods: {
handleClick(selectedValue) {
this.selectedValue = '';
if(!selectedValue) {
this.$emit('change', selectedValue);
}
this.showOptions = !this.showOptions;
if (this.showOptions) {
const selectedOption = this.options.find(option => option[this.labelProp] === selectedValue);
if (selectedOption && !selectedOption.isDisabled) {
// 更新dom
this.$nextTick(() => {
// 如果有选中的选项,则将其高亮
const optionIndex = this.options.indexOf(selectedOption);
const optionsList = this.$el.querySelector('.options');
const selectedOptionEl = optionsList.children[optionIndex];
selectedOptionEl.classList.add('active');
})
}
}
},
handleSelect(option) {
if(!option.isDisabled){
this.showOptions = false;
this.$emit('change', option);
}
}
}
}
<style scoped>
.select-container {
position: relative;
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.input-prefix {
padding: 0 5px;
color: #999;
font-size: 14px;
}
.input {
flex: 1;
height: 40px;
line-height: 40px;
padding: 0 10px;
//border: 1px solid #dcdfe6;
border: none;
border-radius: 4px;
font-size: 14px;
}
.input-suffix {
display: flex;
align-items: center;
padding: 0 10px;
color: #999;
font-size: 14px;
cursor: pointer;
}
.options-container {
position: absolute;
top: 45px;
//left: 0;
//right: 0;
background-color: #fff;
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.15);
z-index: 99;
//width: 100%;
//margin: 4px 37px 4px 39px;
flex: 1;
width: -webkit-fill-available;
height: 120px;
overflow: auto;
}
.options {
list-style: none;
margin: 0;
padding: 0;
}
.hidden {
display: none;
}
.option {
height: 40px;
line-height: 40px;
padding: 0 10px;
cursor: pointer;
color: #000000;
}
.option:hover {
background-color: #f5f5f5;
}
.active {
background-color: #eaf2ff;
color: #0075f9;
}
.disabled {
color: #c6c7c9;
}
.iconfont {
font-size: 16px;
}
.icon-xiala:before {
content: '\e645';
}
.icon-xuanzhong:before {
content: '\e648';
}
</style>
2、使用
<template>
<div>
<van-form @submit="onSubmit">
<van-field
v-model="selectedCity"
center
clearable
name='selectedCity'
required
label="短信验证码"
placeholder="请输入短信验证码"
:rules="[{ required: true, message: '请填写用户名' }]"
>
<template #input>
<Select
v-model="selectedCity"
:options="cityOptions"
@change="handlecityChange"
/>
</template>
</van-field>
<div style="margin: 16px;">
<van-button round block type="info" native-type="submit">提交</van-button>
</div>
</van-form>
</div>
</template>
<script>
import Select from './SearchableDropdown.vue';
export default {
name: 'App',
components: { Select },
data() {
return {
cityOptions: [
{ label: '北京', value: 'beijing',isDisabled: false,visible: false },
{ label: '上海', value: 'shanghai',isDisabled: true,visible: false },
{ label: '广州', value: 'guangzhou',isDisabled: false,visible: false},
{ label: '深圳', value: 'shenzhen',isDisabled: false,visible: false},
],
selectedCity: '',
username: null,
};
},
methods: {
handlecityChange(option) {
console.log(option);
this.selectedCity = option.label;
},
onSubmit(value) {
console.log(value);
}
}
};
</script>