index.vue 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. <template>
  2. <div class="app-select" @click="onClick">
  3. <slot :label="inputValue">
  4. <input class="'app-select__input'" v-model="inputValue" :placeholder="placeholder" readonly />
  5. </slot>
  6. <Popup v-model:show="show" position="bottom" teleport="body" round>
  7. <Picker :columns="columns" @cancel="onCancel" @confirm="onConfirm" />
  8. </Popup>
  9. </div>
  10. </template>
  11. <script lang="ts" setup>
  12. import { shallowRef, computed, PropType, watch } from 'vue'
  13. import { Popup, Picker, PickerConfirmEventParams, FieldInstance } from 'vant'
  14. const props = defineProps({
  15. modelValue: {
  16. type: [Number, String]
  17. },
  18. options: {
  19. type: Array,
  20. default: () => ([])
  21. },
  22. optionProps: {
  23. type: Object as PropType<{ label?: string; value?: string; }>,
  24. default: () => ({
  25. label: 'label',
  26. value: 'value'
  27. })
  28. },
  29. readonly: {
  30. type: Boolean,
  31. default: false
  32. },
  33. placeholder: {
  34. type: String,
  35. default: '请选择'
  36. },
  37. })
  38. const emit = defineEmits(['update:show', 'update:modelValue', 'confirm'])
  39. const fieldRef = shallowRef<FieldInstance>()
  40. const show = shallowRef(false) // 是否弹出选择器
  41. const selectedIndex = shallowRef(-1)
  42. const columns = computed(() => {
  43. if (props.options) {
  44. return props.options.map((e) => ({
  45. text: e[props.optionProps.label],
  46. value: e[props.optionProps.value],
  47. }))
  48. }
  49. return []
  50. })
  51. // 当前输入框的值
  52. const inputValue = computed(() => {
  53. const item = props.options[selectedIndex.value]
  54. if (item) {
  55. return item[props.optionProps.label] ?? ''
  56. }
  57. return ''
  58. })
  59. const onClick = () => {
  60. if (!props.readonly) {
  61. show.value = true
  62. }
  63. }
  64. const onCancel = () => {
  65. show.value = false
  66. }
  67. const onConfirm = ({ selectedIndexes: [index], selectedValues: [value] }: PickerConfirmEventParams) => {
  68. show.value = false
  69. if (selectedIndex.value !== index) {
  70. // 更新当前选中的值
  71. selectedIndex.value = index
  72. fieldRef.value?.validate()
  73. emit('update:modelValue', value)
  74. emit('confirm', value, index)
  75. }
  76. }
  77. watch(() => [props.modelValue, props.options], ([value, items]) => {
  78. selectedIndex.value = items.findIndex((e) => e[props.optionProps.value]?.toString() === value?.toString())
  79. }, {
  80. immediate: true
  81. })
  82. </script>
  83. <style lang="less" scoped>
  84. @import './index.less';
  85. </style>