<uni-combox
v-if="dataSource && dataSource.length > 0"
labelKey="shelves_code"
valueKey="shelves_id"
:candidates="dataSource"
v-model="selectValue"
emptyTips="这里啥都没有"
placeholder="请选择所在城市"
@input="comboxInputHandle"
></uni-combox>
const dataSource = ref([{ shelves_id: 0, shelves_code: 'aa' }])
<template>
<view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
<view v-if="label" class="uni-combox__label" :style="labelStyle">
<text>{{ label }}</text>
</view>
<view class="uni-combox__input-box">
<input
class="uni-combox__input"
type="text"
:focus="firstFocus"
:placeholder="placeholder"
placeholder-class="uni-combox__input-plac"
v-model.trim="inputVal"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
@confirm="onEnter"
/>
<uni-icons
:type="showSelector ? 'top' : 'bottom'"
size="14"
color="#999"
@tap="toggleSelector"
/>
</view>
<view class="uni-combox__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-combox__selector-scroll">
<view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
<text>{{ emptyTips }}</text>
</view>
<view
class="uni-combox__selector-item"
v-for="(item, index) in filterCandidates"
:key="index"
@tap="onSelectorClick(index)"
>
<text>{{ item[`${labelKey}`] }}</text>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
name: 'uniCombox',
emits: ['input', 'update:modelValue', 'scan-success'],
props: {
border: {
type: Boolean,
default: true,
},
label: {
type: String,
default: '',
},
labelWidth: {
type: String,
default: 'auto',
},
placeholder: {
type: String,
default: '',
},
candidates: {
type: Array,
default() {
return []
},
},
emptyTips: {
type: String,
default: '无匹配项',
},
labelKey: {
type: String,
default: 'dictName',
},
valueKey: {
type: String,
default: 'dictId',
},
modelValue: {
type: [String, Number],
default: '',
},
},
data() {
return {
showSelector: false,
firstFocus: false,
inputVal: '',
dictVal: '',
filterCandidates: [],
}
},
computed: {
labelStyle() {
return this.labelWidth === 'auto' ? '' : `width: ${this.labelWidth}`
},
filterCandidatesLength() {
return this.filterCandidates.length
},
},
watch: {
modelValue: {
handler(newVal) {
if (this.candidates.length > 0) {
const selectedItem = this.candidates.find((item) => item[this.valueKey] === newVal)
if (selectedItem) {
this.inputVal = selectedItem[this.labelKey]
}
}
},
immediate: true,
},
candidates: {
handler(newCandidates) {
if (newCandidates.length > 0 && this.dictVal) {
const obj = newCandidates.find((item) => item[this.valueKey] === this.dictVal)
if (obj) {
this.inputVal = obj[this.labelKey]
}
}
this.filterCandidates = newCandidates.filter((item) =>
item[this.labelKey].toString().includes(this.inputVal),
)
},
immediate: true,
},
},
methods: {
focusEvent() {
this.firstFocus = false
this.$nextTick(() => {
this.firstFocus = true
})
},
toggleSelector() {
this.showSelector = !this.showSelector
},
onFocus() {
this.filterCandidates = this.candidates.filter((item) =>
item[this.labelKey].toString().includes(this.inputVal),
)
this.showSelector = true
},
onBlur() {
setTimeout(() => {
this.showSelector = false
}, 150)
},
onSelectorClick(index) {
const selectedItem = this.filterCandidates[index]
this.dictVal = selectedItem[this.valueKey]
this.inputVal = selectedItem[this.labelKey]
this.showSelector = false
this.$emit('input', this.dictVal)
this.$emit('update:modelValue', this.dictVal)
},
onInput() {
this.filterCandidates = this.candidates.filter((item) =>
item[this.labelKey].toString().includes(this.inputVal),
)
this.$emit('input', this.dictVal)
this.$emit('update:modelValue', this.dictVal)
},
// 处理扫码事件
changeScanshelvesHandel() {
uni.scanCode({
scanType: ['barCode', 'qrCode', 'datamatrix', 'pdf417'],
success: (res) => {
this.inputVal = res.result // 设置扫码返回的值
this.filterCandidates = this.candidates.filter((item) =>
item[this.labelKey].toString().includes(this.inputVal),
)
// this.dictVal = res.result // 设置筛选后的值
const selectedItem = this.filterCandidates.find((item) =>
item[this.labelKey].toString().includes(this.inputVal.trim()),
)
if (selectedItem) {
// 如果找到匹配项,更新 dictVal 和 inputVal
this.dictVal = selectedItem[this.valueKey]
this.inputVal = selectedItem[this.labelKey]
// Emit the scan result to the parent component
this.$emit('scan-success', res.result) // 将扫码结果传递给父组件
this.$emit('input', this.dictVal)
this.$emit('update:modelValue', this.dictVal)
}
},
})
},
// 回车事件处理函数
onEnter() {
const selectedItem = this.filterCandidates.find((item) =>
item[this.labelKey].toString().includes(this.inputVal.trim()),
)
if (selectedItem) {
// 如果找到匹配项,更新 dictVal 和 inputVal
this.dictVal = selectedItem[this.valueKey]
this.inputVal = selectedItem[this.labelKey]
// 更新父组件中的值
this.$emit('input', this.dictVal) // 触发输入事件
this.$emit('update:modelValue', this.dictVal) // 更新 modelValue
}
},
},
}
</script>
<style lang="scss">
.uni-combox {
font-size: 14px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 6px 10px;
position: relative;
display: flex;
flex-direction: row;
align-items: center;
}
.uni-combox__label {
font-size: 16px;
line-height: 22px;
padding-right: 10px;
color: #999999;
}
.uni-combox__input-box {
position: relative;
display: flex;
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-combox__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-combox__input-plac {
font-size: 14px;
color: #999;
}
.uni-combox__selector {
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #ffffff;
border: 1px solid #ebeef5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 2;
padding: 4px 0;
}
.uni-combox__selector-scroll {
max-height: 200px;
box-sizing: border-box;
}
.uni-combox__selector-empty,
.uni-combox__selector-item {
display: flex;
cursor: pointer;
line-height: 36px;
font-size: 14px;
text-align: center;
padding: 0px 10px;
}
.uni-combox__selector-item:hover {
background-color: #f9f9f9;
}
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #ebeef5;
}
.uni-popper__arrow::after {
content: ' ';
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-combox__no-border {
border: none;
}
</style>