| | |
| | | <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> |
| | | <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>
|