New file |
| | |
| | | <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" :placeholder="placeholder" |
| | | placeholder-class="uni-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus" |
| | | @blur="onBlur" /> |
| | | <uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector"> |
| | | </uni-icons> |
| | | </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" |
| | | @click="onSelectorClick(index)"> |
| | | <text>{{item}}</text> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | /** |
| | | * 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 组合框的值 |
| | | */ |
| | | export default { |
| | | name: 'uniCombox', |
| | | emits: ['input', 'update:modelValue'], |
| | | 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: '无匹配项' |
| | | }, |
| | | // #ifndef VUE3 |
| | | value: { |
| | | type: [String, Number], |
| | | default: '' |
| | | }, |
| | | // #endif |
| | | // #ifdef VUE3 |
| | | modelValue: { |
| | | type: [String, Number], |
| | | default: '' |
| | | }, |
| | | // #endif |
| | | }, |
| | | data() { |
| | | return { |
| | | showSelector: false, |
| | | inputVal: '' |
| | | } |
| | | }, |
| | | computed: { |
| | | labelStyle() { |
| | | if (this.labelWidth === 'auto') { |
| | | return "" |
| | | } |
| | | return `width: ${this.labelWidth}` |
| | | }, |
| | | filterCandidates() { |
| | | return this.candidates.filter((item) => { |
| | | return item.toString().indexOf(this.inputVal) > -1 |
| | | }) |
| | | }, |
| | | filterCandidatesLength() { |
| | | return this.filterCandidates.length |
| | | } |
| | | }, |
| | | watch: { |
| | | // #ifndef VUE3 |
| | | value: { |
| | | handler(newVal) { |
| | | this.inputVal = newVal |
| | | }, |
| | | immediate: true |
| | | }, |
| | | // #endif |
| | | // #ifdef VUE3 |
| | | modelValue: { |
| | | handler(newVal) { |
| | | this.inputVal = newVal |
| | | }, |
| | | immediate: true |
| | | }, |
| | | // #endif |
| | | }, |
| | | methods: { |
| | | toggleSelector() { |
| | | this.showSelector = !this.showSelector |
| | | }, |
| | | onFocus() { |
| | | this.showSelector = true |
| | | }, |
| | | onBlur() { |
| | | setTimeout(() => { |
| | | this.showSelector = false |
| | | }, 153) |
| | | }, |
| | | onSelectorClick(index) { |
| | | this.inputVal = this.filterCandidates[index] |
| | | this.showSelector = false |
| | | this.$emit('input', this.inputVal) |
| | | this.$emit('update:modelValue', this.inputVal) |
| | | }, |
| | | onInput() { |
| | | setTimeout(() => { |
| | | this.$emit('input', this.inputVal) |
| | | this.$emit('update:modelValue', this.inputVal) |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .uni-combox { |
| | | font-size: 14px; |
| | | border: 1px solid #DCDFE6; |
| | | border-radius: 4px; |
| | | padding: 6px 10px; |
| | | position: relative; |
| | | /* #ifndef APP-NVUE */ |
| | | display: flex; |
| | | /* #endif */ |
| | | // height: 40px; |
| | | flex-direction: row; |
| | | align-items: center; |
| | | // border-bottom: solid 1px #DDDDDD; |
| | | } |
| | | |
| | | .uni-combox__label { |
| | | font-size: 16px; |
| | | line-height: 22px; |
| | | padding-right: 10px; |
| | | color: #999999; |
| | | } |
| | | |
| | | .uni-combox__input-box { |
| | | position: relative; |
| | | /* #ifndef APP-NVUE */ |
| | | display: flex; |
| | | /* #endif */ |
| | | 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 { |
| | | /* #ifndef APP-NVUE */ |
| | | box-sizing: border-box; |
| | | /* #endif */ |
| | | 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 { |
| | | /* #ifndef APP-NVUE */ |
| | | max-height: 200px; |
| | | box-sizing: border-box; |
| | | /* #endif */ |
| | | } |
| | | |
| | | .uni-combox__selector-empty, |
| | | .uni-combox__selector-item { |
| | | /* #ifndef APP-NVUE */ |
| | | display: flex; |
| | | cursor: pointer; |
| | | /* #endif */ |
| | | line-height: 36px; |
| | | font-size: 14px; |
| | | text-align: center; |
| | | // border-bottom: solid 1px #DDDDDD; |
| | | padding: 0px 10px; |
| | | } |
| | | |
| | | .uni-combox__selector-item:hover { |
| | | background-color: #f9f9f9; |
| | | } |
| | | |
| | | .uni-combox__selector-empty:last-child, |
| | | .uni-combox__selector-item:last-child { |
| | | /* #ifndef APP-NVUE */ |
| | | border-bottom: none; |
| | | /* #endif */ |
| | | } |
| | | |
| | | // picker 弹出层通用的指示小三角 |
| | | .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 { |
| | | filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03)); |
| | | 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> |