cwg-combox.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <template>
  2. <view class="cwg-combox">
  3. <template v-if="disabled">
  4. <view class="disabled-text">{{ innerText }}</view>
  5. </template>
  6. <template v-if="!disabled">
  7. <!-- 可搜索模式 -->
  8. <uni-combox v-if="filterable" v-model="innerText" :candidates="textList" :clearable="clearable" :options="options"
  9. :placeholder="placeholder?placeholder:t('placeholder.choose')" :disabled="disabled" @input="handleComboxChange" />
  10. <!-- 普通下拉模式 -->
  11. <uni-data-select v-else v-model="innerValue" :localdata="options" :clear="clearable"
  12. :placeholder="placeholder?placeholder:t('placeholder.choose')" :multiple="multiple" :disabled="disabled" @change="handleSelectChange" :needSpace="needSpace" :emptyTips="t('Documentary.tradingCenter.item143')">
  13. <template #selected v-if="$slots.selected">
  14. <slot name="selected"></slot>
  15. </template>
  16. </uni-data-select>
  17. </template>
  18. </view>
  19. </template>
  20. <script setup>
  21. import { ref, computed, watch, onMounted } from 'vue'
  22. import { useI18n } from 'vue-i18n'
  23. const { t } = useI18n()
  24. const props = defineProps({
  25. value: [String, Number, Array],
  26. options: {
  27. type: Array,
  28. default: () => []
  29. },
  30. filterable: {
  31. type: Boolean,
  32. default: false
  33. },
  34. placeholder: String,
  35. clearable: {
  36. type: Boolean,
  37. default: true
  38. },
  39. multiple: {
  40. type: Boolean,
  41. default: false
  42. },
  43. disabled: Boolean,
  44. needSpace: {
  45. type: Boolean,
  46. default: false
  47. },
  48. })
  49. const emit = defineEmits(['update:value', 'change'])
  50. /**
  51. * 内部状态
  52. */
  53. const innerValue = ref(props.value)
  54. const innerText = ref()
  55. /**
  56. * 提取 text 列表(给 combox 用)
  57. */
  58. const textList = computed(() =>
  59. props.options.map(item => item.text)
  60. )
  61. /**
  62. * value → text 映射
  63. */
  64. const updateTextByValue = (val) => {
  65. if (!val) {
  66. innerText.value = ''
  67. return
  68. }
  69. const item = props.options.find(i => i.value === val)
  70. innerText.value = item ? item.text : ''
  71. }
  72. /**
  73. * 组件挂载时初始化
  74. */
  75. onMounted(() => {
  76. if (props.value) {
  77. innerValue.value = props.value
  78. updateTextByValue(props.value)
  79. }
  80. })
  81. /**
  82. * value 改变时同步内部状态
  83. */
  84. watch(
  85. () => props.value,
  86. (val) => {
  87. innerValue.value = val
  88. updateTextByValue(val)
  89. }
  90. )
  91. /**
  92. * options 改变时重新计算显示文本(回显)
  93. */
  94. watch(
  95. () => props.options,
  96. () => {
  97. if (props.value) {
  98. updateTextByValue(props.value)
  99. }
  100. },
  101. { deep: true }
  102. )
  103. /**
  104. * 普通 select 改变
  105. */
  106. const handleSelectChange = (val) => {
  107. // console.log(val, props.options, 1111)
  108. innerValue.value = val
  109. updateTextByValue(val)
  110. emit('update:value', val)
  111. emit('change', val)
  112. }
  113. /**
  114. * combox 改变
  115. */
  116. const handleComboxChange = (text) => {
  117. const item = props.options.find(i => i.text === text)
  118. if (item) {
  119. innerValue.value = item.value
  120. emit('update:value', item.value)
  121. emit('change', item.value)
  122. }
  123. }
  124. </script>
  125. <style lang="scss" scoped>
  126. @import "@/uni.scss";
  127. .cwg-combox {
  128. font-size: px2rpx(16);
  129. //background-color: var(--bs-secondary-bg);
  130. /* 穿透修改 uni-data-select 内部列表最大高度,使其可以滚动 */
  131. :deep(.uni-select__selector-scroll) {
  132. max-height: px2rpx(200);
  133. /* 限制最高约 200px (约 5~6 个选项的高度) */
  134. overflow-y: auto;
  135. }
  136. }
  137. .disabled-text {
  138. height: px2rpx(35);
  139. padding: 0 px2rpx(12);
  140. border-radius: px2rpx(4);
  141. line-height: 1;
  142. font-size: px2rpx(16);
  143. background: transparent;
  144. display: flex;
  145. align-items: center;
  146. //justify-content: center;
  147. color: var(--input-disabled-text-color);
  148. border: 1px solid #e5e5e5;
  149. border-radius: 4px;
  150. background-color: var(--input-disabled-bg-color) !important;
  151. }
  152. </style>