select-region.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <template>
  2. <view class="container">
  3. <view v-if="isLoading" class="loading">
  4. <u-loading mode="circle"></u-loading>
  5. </view>
  6. <view v-else class="field-body" @click="handleSelect()">
  7. <view class="field-value oneline-hide">{{ valueText ? valueText: placeholder }}</view>
  8. </view>
  9. <u-select v-model="show" mode="mutil-column-auto" :list="options" :default-value="defaultValue" @confirm="onConfirm"></u-select>
  10. </view>
  11. </template>
  12. <script>
  13. import Emitter from '@/uview-ui/libs/util/emitter'
  14. import { isEmpty } from '@/utils/util'
  15. import RegionModel from '@/common/model/Region'
  16. // 根据选中的value集获取索引集keys
  17. // 用于设置默认选中
  18. const findOptionsKey = (data, searchValue, deep = 1, keys = []) => {
  19. const index = data.findIndex(item => item.value === searchValue[deep - 1])
  20. if (index > -1) {
  21. keys.push(index)
  22. if (data[index].children) {
  23. findOptionsKey(data[index].children, searchValue, ++deep, keys)
  24. }
  25. }
  26. return keys
  27. }
  28. export default {
  29. name: 'SelectRegion',
  30. mixins: [Emitter],
  31. model: {
  32. prop: 'value',
  33. event: 'change'
  34. },
  35. props: {
  36. // v-model 指定选中项
  37. value: {
  38. type: Array,
  39. default: () => {
  40. return []
  41. }
  42. },
  43. // 未选中时的提示文字
  44. placeholder: {
  45. type: String,
  46. default: '请选择省/市/区'
  47. }
  48. },
  49. data() {
  50. return {
  51. // 正在加载
  52. isLoading: true,
  53. // 是否显示
  54. show: false,
  55. // 默认选中的值
  56. defaultValue: [],
  57. // 选中项内容(文本展示)
  58. valueText: '',
  59. // 级联选择器数据
  60. options: []
  61. }
  62. },
  63. watch: {
  64. // 监听v-model
  65. value(val) {
  66. // 设置默认选中的值
  67. this.valueText = val.map(item => item.label).join('/')
  68. this.setDefaultValue(val)
  69. // 将当前的值发送到 u-form-item 进行校验
  70. this.dispatch('u-form-item', 'on-form-change', val)
  71. },
  72. },
  73. created() {
  74. // 获取地区数据
  75. this.getTreeData()
  76. },
  77. methods: {
  78. // 打开选择器
  79. handleSelect() {
  80. this.show = true
  81. },
  82. // 获取地区数据
  83. getTreeData() {
  84. const app = this
  85. app.isLoading = true
  86. RegionModel.getTreeData()
  87. .then(regions => {
  88. console.log(regions);
  89. // 格式化级联选择器数据
  90. this.options = this.getOptions(regions)
  91. })
  92. .finally(() => app.isLoading = false)
  93. },
  94. // 确认选择后的回调
  95. onConfirm(value) {
  96. // 绑定到v-model执行的值
  97. this.$emit('input', value)
  98. this.$emit('change', value)
  99. },
  100. /**
  101. * 设置默认选中的值
  102. * 该操作是为了每次打开选择器时聚焦到上次选择
  103. * @param {Object} value
  104. */
  105. setDefaultValue(value) {
  106. const values = value.map(item => item.value)
  107. const options = this.options
  108. this.defaultValue = findOptionsKey(options, values)
  109. },
  110. /**
  111. * 格式化级联选择器数据
  112. * @param {*} regions 地区数据
  113. */
  114. getOptions(regions) {
  115. const { getOptions, getChildren } = this
  116. const options = []
  117. for (const index in regions) {
  118. const item = regions[index]
  119. const children = getChildren(item)
  120. const optionItem = {
  121. value: item.id,
  122. label: item.name
  123. }
  124. if (children !== false) {
  125. optionItem.children = getOptions(children)
  126. }
  127. options.push(optionItem)
  128. }
  129. return options
  130. },
  131. // 获取子集地区
  132. getChildren(item) {
  133. if (item.city) {
  134. return item.city
  135. }
  136. if (item.region) {
  137. return item.region
  138. }
  139. return false
  140. }
  141. }
  142. }
  143. </script>
  144. <style lang="scss" scoped>
  145. .container {
  146. width: 100%;
  147. }
  148. .loading {
  149. padding-left: 10rpx;
  150. // text-align: center;
  151. }
  152. </style>