cwg-combox.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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"
  9. :placeholder="placeholder" :disabled="disabled" @input="handleComboxChange" />
  10. <!-- 普通下拉模式 -->
  11. <uni-data-select v-else v-model="innerValue" :localdata="options" :clear="clearable"
  12. :placeholder="placeholder" :multiple="multiple" :disabled="disabled" @change="handleSelectChange">
  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. })
  45. const emit = defineEmits(['update:value', 'change'])
  46. /**
  47. * 内部状态
  48. */
  49. const innerValue = ref(props.value)
  50. const innerText = ref()
  51. /**
  52. * 提取 text 列表(给 combox 用)
  53. */
  54. const textList = computed(() =>
  55. props.options.map(item => item.text)
  56. )
  57. /**
  58. * value → text 映射
  59. */
  60. const updateTextByValue = (val) => {
  61. if (!val) {
  62. innerText.value = ''
  63. return
  64. }
  65. const item = props.options.find(i => i.value === val)
  66. innerText.value = item ? item.text : ''
  67. }
  68. /**
  69. * 组件挂载时初始化
  70. */
  71. onMounted(() => {
  72. if (props.value) {
  73. innerValue.value = props.value
  74. updateTextByValue(props.value)
  75. }
  76. })
  77. /**
  78. * value 改变时同步内部状态
  79. */
  80. watch(
  81. () => props.value,
  82. (val) => {
  83. innerValue.value = val
  84. updateTextByValue(val)
  85. }
  86. )
  87. /**
  88. * options 改变时重新计算显示文本(回显)
  89. */
  90. watch(
  91. () => props.options,
  92. () => {
  93. if (props.value) {
  94. updateTextByValue(props.value)
  95. }
  96. },
  97. { deep: true }
  98. )
  99. /**
  100. * 普通 select 改变
  101. */
  102. const handleSelectChange = (val) => {
  103. // console.log(val, props.options, 1111)
  104. innerValue.value = val
  105. updateTextByValue(val)
  106. emit('update:value', val)
  107. emit('change', val)
  108. }
  109. /**
  110. * combox 改变
  111. */
  112. const handleComboxChange = (text) => {
  113. const item = props.options.find(i => i.text === text)
  114. if (item) {
  115. innerValue.value = item.value
  116. emit('update:value', item.value)
  117. emit('change', item.value)
  118. }
  119. }
  120. </script>
  121. <style lang="scss" scoped>
  122. @import "@/uni.scss";
  123. .cwg-combox {
  124. font-size: px2rpx(16);
  125. //background-color: var(--bs-secondary-bg);
  126. /* 穿透修改 uni-data-select 内部列表最大高度,使其可以滚动 */
  127. :deep(.uni-select__selector-scroll) {
  128. max-height: px2rpx(200);
  129. /* 限制最高约 200px (约 5~6 个选项的高度) */
  130. overflow-y: auto;
  131. }
  132. }
  133. .disabled-text {
  134. height: px2rpx(35);
  135. padding: 0 px2rpx(12);
  136. border-radius: px2rpx(4);
  137. line-height: 1;
  138. font-size: px2rpx(16);
  139. background: transparent;
  140. display: flex;
  141. align-items: center;
  142. //justify-content: center;
  143. color: #d5d5d5;
  144. border: 1px solid #e5e5e5;
  145. border-radius: 4px;
  146. background-color: #f5f7fa !important;
  147. }
  148. </style>