mx-picker.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <template>
  2. <view class="flex-1 fx-row fx-end-cen gap-10" @click="handleClick">
  3. <view v-if="valueMode" class="text-sm">{{ display }}</view>
  4. <view v-else class="text-sm text-light">{{ placeholder }}</view>
  5. <uv-icon name="arrow-down"/>
  6. <uv-picker ref="picker" :columns="columns" :default-index="defaultIndex" :title="title" :key-name="labelProp"
  7. @confirm="handleConfirm" @change="handleChange"/>
  8. </view>
  9. </template>
  10. <script setup>
  11. import {computed, getCurrentInstance, ref} from 'vue'
  12. import {empty} from "@/uni_modules/uv-ui-tools/libs/function/test";
  13. import _ from "lodash";
  14. import {createPropDefine} from "@/utils";
  15. import {findTreePath} from "@/utils/tree-helper";
  16. import {autoFormValidate} from "@/utils/uni-helper";
  17. const picker = ref(null)
  18. const props = defineProps({
  19. title: createPropDefine(''),
  20. placeholder: createPropDefine(''),
  21. data: createPropDefine([], Array),
  22. modelValue: createPropDefine(null, [String, Number, Object]),
  23. labelProp: createPropDefine(''),
  24. valueProp: createPropDefine(''),
  25. emptyDisplay: createPropDefine(''),
  26. treeProp: createPropDefine('')
  27. })
  28. const emits = defineEmits(['change', 'update:modelValue'])
  29. const instance = getCurrentInstance()
  30. const valueMode = computed(() => !empty(props.modelValue) || !!props.emptyDisplay)
  31. const display = computed(() => {
  32. if (empty(props.modelValue) && !!props.emptyDisplay) return props.emptyDisplay
  33. return getLabel(current.value) || props.emptyDisplay
  34. })
  35. const currentPath = computed(() => findTreePath(props.data, item => getValue(item) == props.modelValue, props.treeProp))
  36. const current = computed(() => _.last(currentPath.value))
  37. const columns = ref([])
  38. const defaultIndex = ref([])
  39. const handleClick = function () {
  40. setDefaultColumnsAndIndexs()
  41. picker.value.open()
  42. }
  43. // columnIndex 正在改变的列 > index 改变后的序号 > indexs 当前选中的全部序号
  44. // > value 当前选中的全部元素 > values 当前columns
  45. const handleConfirm = function ({value}) {
  46. const selected = _.last(value)
  47. const selectedValue = getValue(selected)
  48. emits('update:modelValue', selectedValue)
  49. emits('change', selected)
  50. // try trigger uv-form validate
  51. autoFormValidate(instance, 'change')
  52. }
  53. const handleChange = function ({columnIndex, value}) {
  54. if (!props.treeProp) return // 不是树形结构
  55. if (columnIndex == value.length - 1) return // 操作的是最后一列
  56. const changToValue = getValue(value[columnIndex])
  57. const {cols, idxes} = calculateColumnsAndIndexs(changToValue)
  58. console.log('calculateColumnsAndIndexs', cols, idxes)
  59. columns.value = cols
  60. picker.value.setIndexs(idxes, true)
  61. }
  62. const setDefaultColumnsAndIndexs = function () {
  63. const {cols, idxes} = calculateColumnsAndIndexs(props.modelValue)
  64. columns.value = cols
  65. defaultIndex.value = idxes
  66. }
  67. /*
  68. * @description 根据给定的值计算picker所需要的columns和indexs
  69. * */
  70. const calculateColumnsAndIndexs = function (value, autoEnd = true) {
  71. const {data, treeProp} = props
  72. const cols = []
  73. const idxes = []
  74. const path = findTreePath(data, n => getValue(n) == value, treeProp)
  75. // auto end // 指定的条件,可能查出来的是中间某列的值,此时自动帮它选中至最后一列
  76. if (autoEnd && treeProp && path?.length) {
  77. let final = _.last(path)
  78. while (final[treeProp]?.length) {
  79. final = final[treeProp][0]
  80. path.push(final)
  81. }
  82. }
  83. // modelValue logic
  84. let prevNode = data
  85. _.forEach(path, item => {
  86. const idx = prevNode.findIndex(n => getValue(n) == getValue(item))
  87. if (idx < 0) {
  88. // 无效值,停止迭代
  89. cols.length = 0
  90. idxes.length = 0
  91. return false // lodash.forEach接收到false返回会终止迭代
  92. }
  93. cols.push(prevNode)
  94. idxes.push(idx)
  95. prevNode = _.get(prevNode, idx + '.' + treeProp)
  96. })
  97. // default logic
  98. if (!cols.length && data.length) {
  99. prevNode = data
  100. do {
  101. cols.push(prevNode)
  102. idxes.push(0)
  103. prevNode = _.get(prevNode, '0.' + props.treeProp)
  104. } while (prevNode)
  105. }
  106. return {cols, idxes}
  107. }
  108. const getValue = item => _.get(item, props.valueProp, item)
  109. const getLabel = item => _.get(item, props.labelProp, item)
  110. defineExpose({current, currentPath})
  111. </script>
  112. <style scoped>
  113. </style>