PickerAddress.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <template>
  2. <view class="picker-address">
  3. <uni-popup ref="popRef">
  4. <view class="picker-address-content">
  5. <view class="picker-address-top">
  6. <view class="picker-address-action cancel" @click="onCancel">取消</view>
  7. <view class="picker-address-action confirm" @click="onConfirm">确定</view>
  8. </view>
  9. <picker-view indicator-class='is-selected' :value="areaIndex" @change="onAreaChange">
  10. <picker-view-column>
  11. <view class="addr-item" :class="areaIndex[0] == index ?'selected':''"
  12. v-for="(item, index) in areaList[0]" :key="index">
  13. {{ item.name }}
  14. </view>
  15. </picker-view-column>
  16. <picker-view-column>
  17. <view class="addr-item" :class="areaIndex[1] == index ?'selected':''"
  18. v-for="(item, index) in areaList[1]" :key="index">
  19. {{ item.name }}
  20. </view>
  21. </picker-view-column>
  22. <picker-view-column>
  23. <view class="addr-item" :class="areaIndex[2] == index ?'selected':''"
  24. v-for="(item, index) in areaList[2]" :key="index">
  25. {{ item.name }}
  26. </view>
  27. </picker-view-column>
  28. </picker-view>
  29. </view>
  30. </uni-popup>
  31. </view>
  32. </template>
  33. <script lang="ts" setup>
  34. import { ref, onMounted, computed, watch } from 'vue'
  35. import dataTree from "@/static/json/pca-code.json"
  36. const emits = defineEmits(['change'])
  37. const props = defineProps({
  38. province: {
  39. type: String,
  40. default: ""
  41. },
  42. city: {
  43. type: String,
  44. default: ""
  45. },
  46. area: {
  47. type: String,
  48. default: ""
  49. },
  50. })
  51. watch(
  52. () => props.province,
  53. () => {
  54. if (props.province){
  55. updateAreaIndex(props.province,props.city,props.area)
  56. }
  57. }
  58. )
  59. const popRef = ref()
  60. const areaList = ref([[], [], []])//todo类型
  61. const areaIndex = ref([0, 0, 0])
  62. const provinceName = computed(() => {
  63. return areaList.value[0][areaIndex.value[0]] ? areaList.value[0][areaIndex.value[0]]["name"] : '省';
  64. })
  65. const cityName = computed(() => {
  66. return areaList.value[1][areaIndex.value[1]] ? areaList.value[1][areaIndex.value[1]]["name"] : '市';
  67. })
  68. const areaName = computed(() => {
  69. return areaList.value[2][areaIndex.value[2]] ? areaList.value[2][areaIndex.value[2]]["name"] : '区';
  70. })
  71. const onCancel = ()=> {
  72. popRef.value.close()
  73. }
  74. const onConfirm = async()=> {
  75. const data = {
  76. province:provinceName.value,
  77. city:cityName.value,
  78. area:areaName.value,
  79. }
  80. emits('change',data);
  81. onCancel()
  82. }
  83. const onAreaChange = async (e) => {
  84. const originalIndex = [...areaIndex.value];
  85. console.log("原来", areaIndex.value)
  86. areaIndex.value = e.detail.value
  87. console.log("现在", areaIndex.value)
  88. if (originalIndex[0] !== areaIndex.value[0]) {
  89. areaIndex.value[1] = 0
  90. areaIndex.value[2] = 0
  91. await initArea();
  92. } else if (originalIndex[1] !== areaIndex.value[1]) {
  93. areaIndex.value[2] = 0
  94. await getCity();
  95. }
  96. }
  97. const openPop = () => {
  98. popRef.value.open('bottom')
  99. }
  100. // 获取所有省
  101. const getProvinces = (data) => {
  102. return data.map(province => ({
  103. id: province.code,
  104. name: province.name ,
  105. }));
  106. };
  107. // 匹配省里面的所有市
  108. const getCitiesByProvinceIndex = (data, index) => {
  109. if (data[index] && data[index].children) {
  110. return data[index].children.map(city => ({
  111. id: city.code,
  112. name: city.name
  113. }));
  114. }
  115. return [];
  116. };
  117. // 匹配省里面的市的区
  118. const getAreasByCityIndex = (data, provinceIndex, cityIndex) => {
  119. if (data[provinceIndex] && data[provinceIndex].children &&
  120. data[provinceIndex].children[cityIndex] && data[provinceIndex].children[cityIndex].children) {
  121. return data[provinceIndex].children[cityIndex].children.map(area => ({
  122. id: area.code,
  123. name: area.name
  124. }));
  125. }
  126. return [];
  127. };
  128. //初始化地址选择器
  129. const initArea = async () => {
  130. //获取省
  131. let result = getProvinces(dataTree)
  132. console.log("省",result)
  133. if (result == null) {
  134. console.log("获取省出错");
  135. return false;
  136. } else {
  137. areaList.value.splice(0, 1, result);
  138. await getCity();
  139. }
  140. }
  141. //获取市
  142. const getCity = async () => {
  143. let pid = areaIndex.value[0];
  144. let result = getCitiesByProvinceIndex(dataTree, pid)
  145. console.log("对应市",result)
  146. if (result == null) {
  147. console.log("获取市出错");
  148. return false;
  149. } else {
  150. areaList.value.splice(1, 1, result);
  151. await getArea();
  152. }
  153. }
  154. //获取区
  155. const getArea = async () => {
  156. let pid = areaIndex.value[0];
  157. let cid = areaIndex.value[1];
  158. let result = getAreasByCityIndex(dataTree,pid,cid)
  159. console.log("对应区",result)
  160. if (result == null) {
  161. console.log("获取区出错");
  162. return false;
  163. } else {
  164. areaList.value.splice(2, 1, result);
  165. }
  166. }
  167. const findIndexes = (dataTree, provinceName, cityName, areaName) => {
  168. let provinceIndex = 0;
  169. let cityIndex = 0;
  170. let areaIndex = 0;
  171. dataTree.some((province, pIndex) => {
  172. if (province.name === provinceName) {
  173. provinceIndex = pIndex;
  174. return province.children.some((city, cIndex) => {
  175. if (city.name === cityName) {
  176. cityIndex = cIndex;
  177. return city.children.some((area, aIndex) => {
  178. if (area.name === areaName) {
  179. areaIndex = aIndex;
  180. return true;
  181. }
  182. return false;
  183. });
  184. }
  185. return false;
  186. });
  187. }
  188. return false;
  189. });
  190. return [provinceIndex, cityIndex, areaIndex];
  191. }
  192. const updateAreaIndex = (provinceName, cityName, areaName) => {
  193. const indexes = findIndexes(dataTree, provinceName, cityName, areaName);
  194. areaIndex.value = indexes;
  195. }
  196. onMounted(async () => {
  197. if (props.province){
  198. updateAreaIndex(props.province,props.city,props.area)
  199. }
  200. await initArea();
  201. // getInfo()
  202. })
  203. defineExpose({ openPop })
  204. </script>
  205. <style lang="scss" scoped>
  206. .picker-address {
  207. .picker-address-content {
  208. background-color: #fff;
  209. border-radius: 16rpx 16rpx 0 0;
  210. .picker-address-top {
  211. height: 96rpx;
  212. @include flex-between;
  213. border-bottom: 1px solid $uni-border-color;
  214. .picker-address-action {
  215. font-size: $uni-font-size-xl;
  216. line-height: $uni-line-height-xl;
  217. @include flex;
  218. padding: 0 32rpx;
  219. &.cancel {
  220. color: $uni-text-color !important;
  221. }
  222. &.confirm {
  223. color: $uni-color-primary;
  224. }
  225. }
  226. }
  227. .addr-item {
  228. height: 96rpx !important;
  229. font-size: $uni-font-size-xl;
  230. line-height: $uni-line-height-xl;
  231. @include flex-center;
  232. &.selected {
  233. font-size: $uni-font-size-xxl;
  234. line-height: $uni-line-height-xxl;
  235. }
  236. }
  237. }
  238. :deep(uni-picker-view) {
  239. margin-top: 24rpx;
  240. }
  241. :deep(.is-selected) {
  242. height: 96rpx !important;
  243. color: $uni-text-color;
  244. font-size: $uni-font-size-xxl;
  245. line-height: $uni-line-height-xxl;
  246. }
  247. :deep(.uni-picker-view-wrapper) {
  248. overflow: visible;
  249. uni-picker-view-column {
  250. overflow: visible;
  251. &:first-child {
  252. .is-selected {
  253. &::before,
  254. &::after {
  255. left: -32rpx;
  256. }
  257. }
  258. }
  259. &:last-child {
  260. .is-selected {
  261. &::before,
  262. &::after {
  263. right: -32rpx;
  264. }
  265. }
  266. }
  267. }
  268. }
  269. :deep(.uni-picker-view-indicator:before) {
  270. border-top-color: $uni-border-color;
  271. }
  272. :deep(.uni-picker-view-indicator:after) {
  273. border-bottom-color: $uni-border-color;
  274. }
  275. }
  276. picker-view {
  277. width: 100%;
  278. height: 600rpx;
  279. padding: 0 32rpx;
  280. box-sizing: border-box;
  281. overflow: hidden;
  282. }
  283. </style>