cwg-combox.vue 3.5 KB

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