<template> <view class="uni-combox"> <view class="uni-combox-dialog" v-if="isDialogInput && showSelector"> <view class="uni-combox-input"> <input class="uni-combox__input" type="text" :placeholder="selectItem.value ? selectItem.value : placeholder" v-model="inputVal" @input="onInput" @blur="onBlur" :focus="'true'" style="height: 90upx;" /> <uni-icons style="line-height: 90upx;" class="uni-combox__input-arrow" type="close" size="14" @click="clearSelector"></uni-icons> <view class="uni-combox__selector"> <scroll-view scroll-y="true" class="uni-combox__selector-scroll"> <view class="uni-combox__selector-empty" v-if="isLoading"><text>数据加载...</text></view> <view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0 && !isLoading"> <text>{{ emptyTips }}</text> </view> <view v-if="!isLoading" class="uni-combox__selector-item" v-for="(item, index) in filterCandidates" :key="index" @click="onSelectorClick(item)"> <view class="addr_title"> <text>{{ item.value }}</text> </view> <view class="detail_info"> <text>{{item.detail}}</text> </view> </view> </scroll-view> </view> </view> </view> <view v-if="label" class="uni-combox__label" :style="labelStyle"> <text>{{ label }}</text> </view> <view class="uni-combox__input-box"> <input v-if="isDialogInput" class="uni-combox__input" type="text" :placeholder="selectItem.value ? selectItem.value : placeholder" v-model="inputVal" @focus="onFocus" /> <input v-else class="uni-combox__input" type="text" :placeholder="selectItem.value ? selectItem.value : placeholder" v-model="inputVal" @focus="onFocus" @input="onInput" @blur="onBlur" /> <uni-icons v-if="!showSelector && !inputVal" class="uni-combox__input-arrow" type="arrowdown" size="14" @click="toggleSelector"></uni-icons> <uni-icons v-else class="uni-combox__input-arrow" type="close" size="14" @click="clearSelector"></uni-icons> <view class="uni-combox__selector" v-if="!isDialogInput && showSelector"> <scroll-view scroll-y="true" class="uni-combox__selector-scroll"> <view class="uni-combox__selector-empty" v-if="isLoading"><text>数据加载...</text></view> <view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0 && !isLoading"> <text>{{ emptyTips }}</text> </view> <view v-if="!isLoading" class="uni-combox__selector-item" v-for="(item, index) in filterCandidates" :key="index" @click="onSelectorClick(item)"> <view class="addr_title"> <text >{{ item.value }}</text> </view> <view class="detail_info"> <text >{{item.detail}}</text> </view> </view> </scroll-view> </view> </view> </view> </template> <script> import uniIcons from '../uni-icons/uni-icons.vue'; /** * Combox 组合输入框 * @description 组合输入框一般用于既可以输入也可以选择的场景 * @tutorial https://ext.dcloud.net.cn/plugin?id=1261 * @property {String} label 左侧文字 * @property {String} labelWidth 左侧内容宽度 * @property {String} placeholder 输入框占位符 * @property {Array} candidates 候选项列表 * @property {String} emptyTips 筛选结果为空时显示的文字 * @property {String} value 组合框的值 * @property {String} isDialogInput 弹出框输入和选择避免键盘遮挡 */ export default { name: 'uniCombox', components: { uniIcons }, props: { label: { type: String, default: '' }, labelWidth: { type: String, default: 'auto' }, placeholder: { type: String, default: '' }, candidates: { type: Array, default() { return []; } }, emptyTips: { type: String, default: '无匹配项' }, value: { type: String, default: '' }, isDialogInput: { type: Boolean, default: false } }, data() { return { showSelector: false, inputVal: '', isLoading: false, showDowm: true, selectItem: { key: '', value: '' } }; }, computed: { labelStyle() { if (this.labelWidth === 'auto') { return {}; } return { width: this.labelWidth }; }, filterCandidates() { return this.candidates.filter(item => { return item; }); }, filterCandidatesLength() { return this.filterCandidates.length; } }, onLoad() { if(this.value){ this.inputVal = this.value console.log("这里是组件内部值为:"+this.inputVal) } }, watch: { value: { handler(newVal) { if(newVal) { this.candidates.filter(item => { if (this.value === item.key) { this.selectItem = item; this.inputVal = item.value; } }); }else { this.selectItem = { key: '', value: '' } this.inputVal = '' } }, immediate: true }, candidates: { handler(newVal) { this.isLoading = false; }, immediate: true } }, methods: { toggleSelector() { this.showSelector = !this.showSelector; }, clearSelector() { console.log('这里是组件里清除') this.selectItem = { key: '', value: '' }; this.inputVal = ''; this.showSelector = false; this.isLoading = false; this.$emit('clear'); }, onFocus() { console.log('这里是是input foucus') if (this.inputVal) { this.showSelector = false; // this.inputVal = ''; } }, // 组件input失焦 onBlur() { console.log('这里是input失焦') // this.showSelector = !this.showSelector; setTimeout(() => { if (this.selectItem.value) { console.log('这里是this.selectItem.value',this.selectItem.value) const selectItem = JSON.parse(JSON.stringify(this.selectItem)); this.inputVal = selectItem.value; } else { console.log('123') this.inputVal = ''; } // this.showSelector = false; }, 50); }, onSelectorClick(item) { console.log('这类似组件内',item) this.selectItem = item; this.inputVal = item.value; this.showSelector = false; this.$emit('select', item.key, item); }, onInput() { console.log('这类似inputchange',this.inputVal) setTimeout(() => { if (this.inputVal && this.inputVal!=='') { this.isLoading = true; this.showSelector = true; this.$emit('input', this.inputVal); } else { this.isLoading = false; } }); } } }; </script> <style lang="scss" scoped> .uni-combox { /* #ifndef APP-NVUE */ display: flex; /* #endif */ height: 40upx; flex-direction: row; align-items: center; // border-bottom: solid 1px #DDDDDD; } .uni-combox__label { font-size: 28upx; line-height: 40upx; padding-right: 10px; color: #999999; } .uni-combox__input-box { position: relative; /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex: 1; width: 320rpx; flex-direction: row; align-items: center; } .uni-combox__input { flex: 1; font-size: 28upx; } .uni-combox__input-arrow { padding-left: 15upx; padding-right: 15upx; } .uni-combox__selector { box-sizing: border-box; position: absolute; top: 40px; left: -145rpx; right: 150rpx; width: 139%!important; background-color: #FFFFFF; border-radius: 6px; box-shadow: #dddddd 4px 4px 8px, #dddddd -4px -4px 8px; z-index: 2222; } .uni-combox__selector-scroll { max-height: 550upx; box-sizing: border-box; } .uni-combox__selector::before { content: ''; position: absolute; width: 0; height: 0; border-bottom: solid 6px #ffffff; border-right: solid 6px transparent; border-left: solid 6px transparent; left: 50%; top: -6px; margin-left: -6px; } .uni-combox__selector-empty, .uni-combox__selector-item { /* #ifdef APP-NVUE */ display: flex; /* #endif */ line-height: 40upx; font-size: 28upx; text-align: center; border-bottom: solid 1px #dddddd; padding: 4rpx 9rpx; margin: 0px 10px; } .uni-combox__selector-empty{ line-height: 70upx; } .uni-combox__selector-empty:last-child, .uni-combox__selector-item:last-child { border-bottom: none; } .uni-combox-dialog { background: #cccccc7d; position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: 100; } .uni-combox-input { background: #fff; display: -webkit-box; display: -webkit-flex; display: flex; height: 90upx; } .addr_title{ font-weight: 700; font-size: 30rpx; text-align: left; margin-bottom: 0; padding-bottom: 0; margin-top: 10rpx; margin-left: 20rpx; } .detail_info{ text-align: left; color: #CCCCCC; margin-top: 0; padding-top: 0; font-size: 25rpx; margin-left: 20rpx; } </style>