cwg-combox.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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" :disabled="disabled" @change="handleSelectChange" />
  13. </template>
  14. </view>
  15. </template>
  16. <script setup>
  17. import { ref, computed, watch, onMounted } from 'vue'
  18. const props = defineProps({
  19. value: [String, Number],
  20. options: {
  21. type: Array,
  22. default: () => []
  23. },
  24. filterable: {
  25. type: Boolean,
  26. default: false
  27. },
  28. placeholder: String,
  29. clearable: {
  30. type: Boolean,
  31. default: true
  32. },
  33. disabled: Boolean
  34. })
  35. const emit = defineEmits(['update:value', 'change'])
  36. /**
  37. * 内部状态
  38. */
  39. const innerValue = ref(props.value)
  40. const innerText = ref('')
  41. /**
  42. * 提取 text 列表(给 combox 用)
  43. */
  44. const textList = computed(() =>
  45. props.options.map(item => item.text)
  46. )
  47. /**
  48. * value → text 映射
  49. */
  50. const updateTextByValue = (val) => {
  51. if (!val) {
  52. innerText.value = ''
  53. return
  54. }
  55. const item = props.options.find(i => i.value === val)
  56. innerText.value = item ? item.text : ''
  57. }
  58. /**
  59. * 组件挂载时初始化
  60. */
  61. onMounted(() => {
  62. if (props.value) {
  63. innerValue.value = props.value
  64. updateTextByValue(props.value)
  65. }
  66. })
  67. /**
  68. * value 改变时同步内部状态
  69. */
  70. watch(
  71. () => props.value,
  72. (val) => {
  73. innerValue.value = val
  74. updateTextByValue(val)
  75. }
  76. )
  77. /**
  78. * options 改变时重新计算显示文本(回显)
  79. */
  80. watch(
  81. () => props.options,
  82. () => {
  83. if (props.value) {
  84. updateTextByValue(props.value)
  85. }
  86. },
  87. { deep: true }
  88. )
  89. /**
  90. * 普通 select 改变
  91. */
  92. const handleSelectChange = (val) => {
  93. innerValue.value = val
  94. updateTextByValue(val)
  95. emit('update:value', val)
  96. emit('change', val)
  97. }
  98. /**
  99. * combox 改变
  100. */
  101. const handleComboxChange = (text) => {
  102. const item = props.options.find(i => i.text === text)
  103. if (item) {
  104. innerValue.value = item.value
  105. emit('update:value', item.value)
  106. emit('change', item.value)
  107. }
  108. }
  109. </script>
  110. <style lang="scss" scoped>
  111. .disabled-text {
  112. height: px2rpx(35);
  113. padding: 0 px2rpx(12);
  114. border-radius: px2rpx(4);
  115. line-height: px2rpx(35);
  116. font-size: px2rpx(15);
  117. background: #f5f5f5;
  118. color: #d5d5d5;
  119. }
  120. </style>