index.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <template>
  2. <view :style="viewColor">
  3. <view class="address-window" :class="display==true?'on':''">
  4. <view class='title'>请选择所在地区<text class='iconfont icon-guanbi' @tap='close'></text></view>
  5. <view class="address-count">
  6. <view class="address-selected">
  7. <view v-for="(item,index) in selectedArr" :key="index" class="selected-list" :class="{active:index === selectedIndex}" @click="change(item.parent_id, index)">
  8. {{item.name}}
  9. <text class="iconfont icon-xiangyou"></text>
  10. </view>
  11. <view class="selected-list" :class="{active:-1 === selectedIndex}" v-if="showMore" @click="change(-1, -1)">
  12. <text class="iconfont icon-xiangyou"></text>
  13. 请选择
  14. </view>
  15. </view>
  16. <scroll-view scroll-y="true" :scroll-top="scrollTop" class="address-list" @scroll="scroll">
  17. <view v-for="(item,index) in addressList" :key="index" class="list" :class="{active:item.id === activeId}" @click="selected(item)">
  18. <text class="item-name">{{item.name}}</text>
  19. <text v-if="item.id === activeId" class="iconfont icon-duihao2"></text>
  20. </view>
  21. </scroll-view>
  22. </view>
  23. </view>
  24. <view class='mask' catchtouchmove="true" :hidden='display==false' @tap='close'></view>
  25. </view>
  26. </template>
  27. <script>
  28. // +----------------------------------------------------------------------
  29. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  30. // +----------------------------------------------------------------------
  31. // | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
  32. // +----------------------------------------------------------------------
  33. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  34. // +----------------------------------------------------------------------
  35. // | Author: CRMEB Team <admin@crmeb.com>
  36. // +----------------------------------------------------------------------
  37. import {getAddressList} from '@/api/user.js';
  38. import { getCityV2 } from '@/api/api.js';
  39. import { mapGetters } from "vuex";
  40. const CACHE_ADDRESS = {};
  41. export default {
  42. props: {
  43. display: {
  44. type: Boolean,
  45. default: true
  46. },
  47. address: Array,
  48. },
  49. data() {
  50. return {
  51. active: 0,
  52. //地址列表
  53. addressList: [],
  54. selectedArr: [],
  55. selectedIndex: -1,
  56. is_loading: false,
  57. old: { scrollTop: 0 },
  58. scrollTop: 0
  59. };
  60. },
  61. computed:{
  62. ...mapGetters(['viewColor']),
  63. activeId(){
  64. return this.selectedIndex == -1 ? 0 : this.selectedArr[this.selectedIndex].id
  65. },
  66. showMore(){
  67. return this.selectedArr.length ? this.selectedArr[this.selectedArr.length - 1].snum > 0 : true
  68. }
  69. },
  70. watch:{
  71. address(n){
  72. this.selectedArr = n ? [...n] : []
  73. },
  74. display(n){
  75. if(!n) {
  76. this.addressList = [];
  77. this.selectedArr = this.address ? [...this.address] : [];
  78. this.selectedIndex = -1;
  79. this.is_loading = false;
  80. }else{
  81. this.loadAddress(0)
  82. }
  83. }
  84. },
  85. mounted() {
  86. this.loadAddress(0)
  87. },
  88. methods: {
  89. change(pid,index){
  90. if(this.selectedIndex == index) return;
  91. if(pid === -1){
  92. pid = this.selectedArr.length ? this.selectedArr[this.selectedArr.length -1].id : 0;
  93. }
  94. this.selectedIndex = index;
  95. this.loadAddress(pid);
  96. },
  97. loadAddress(pid){
  98. if(CACHE_ADDRESS[pid]){
  99. this.addressList = CACHE_ADDRESS[pid];
  100. return ;
  101. }
  102. this.is_loading = true;
  103. getCityV2(pid).then(res=>{
  104. this.is_loading = false;
  105. CACHE_ADDRESS[pid] = res.data;
  106. this.addressList = res.data;
  107. })
  108. this.goTop()
  109. },
  110. selected(item){
  111. if(this.is_loading) return;
  112. if(this.selectedIndex > -1){
  113. this.selectedArr.splice(this.selectedIndex + 1,999)
  114. this.selectedArr[this.selectedIndex] = item;
  115. this.selectedIndex = -1;
  116. }else if(!item.parent_id){
  117. this.selectedArr = [item];
  118. }else{
  119. this.selectedArr.push(item);
  120. }
  121. if(item.snum){
  122. this.loadAddress(item.id);
  123. } else {
  124. this.$emit('submit', [...this.selectedArr]);
  125. this.$emit('changeClose');
  126. }
  127. this.goTop()
  128. },
  129. close: function() {
  130. this.$emit('changeClose');
  131. },
  132. scroll : function(e) {
  133. this.old.scrollTop = e.detail.scrollTop
  134. },
  135. goTop: function(e) {
  136. this.scrollTop = this.old.scrollTop
  137. this.$nextTick(() => {
  138. this.scrollTop = 0
  139. });
  140. }
  141. }
  142. }
  143. </script>
  144. <style scoped lang="scss">
  145. .address-window {
  146. background-color: #fff;
  147. position: fixed;
  148. bottom: 0;
  149. left: 0;
  150. width: 100%;
  151. z-index: 101;
  152. border-radius: 30rpx 30rpx 0 0;
  153. transform: translate3d(0, 100%, 0);
  154. transition: all .3s cubic-bezier(.25, .5, .5, .9);
  155. }
  156. .address-window.on {
  157. transform: translate3d(0, 0, 0);
  158. }
  159. .address-window .title {
  160. font-size: 32rpx;
  161. font-weight: bold;
  162. text-align: center;
  163. height: 123rpx;
  164. line-height: 123rpx;
  165. position: relative;
  166. }
  167. .address-window .title .iconfont {
  168. position: absolute;
  169. right: 30rpx;
  170. color: #8a8a8a;
  171. font-size: 35rpx;
  172. }
  173. .address-count{
  174. .address-selected{
  175. padding: 0 30rpx;
  176. margin-top: 10rpx;
  177. position: relative;
  178. padding-bottom: 20rpx;
  179. border-bottom: 2rpx solid #f7f7f7;
  180. }
  181. .selected-list{
  182. font-size: 26rpx;
  183. color: #282828;
  184. line-height: 50rpx;
  185. padding-bottom: 10rpx;
  186. padding-left: 60rpx;
  187. position: relative;
  188. &.active{
  189. color: #e28d54;
  190. }
  191. &:before,&:after{
  192. content: '';
  193. display: block;
  194. position: absolute;
  195. }
  196. &:before{
  197. width: 4rpx;
  198. height: 100%;
  199. background-color: var(--view-theme);
  200. top: 0;
  201. left: 10rpx;
  202. }
  203. &:after{
  204. width: 12rpx;
  205. height: 12rpx;
  206. background: var(--view-theme);
  207. border-radius: 100%;
  208. left: 6rpx;
  209. top: 50%;
  210. margin-top: -8rpx;
  211. }
  212. &:first-child,&:last-child{
  213. &:before{
  214. height: 50%;
  215. }
  216. }
  217. &:first-child{
  218. &:before{
  219. top: auto;
  220. bottom: 0;
  221. }
  222. }
  223. .iconfont{
  224. font-size: 20rpx;
  225. float: right;
  226. color: #dddddd;
  227. }
  228. }
  229. scroll-view{
  230. height: 550rpx;
  231. }
  232. .address-list{
  233. padding: 0 30rpx;
  234. margin-top: 20rpx;
  235. box-sizing: border-box;
  236. .list{
  237. .iconfont{
  238. float: right;
  239. color: #ddd;
  240. font-size: 22rpx;
  241. }
  242. .item-name{
  243. display: inline-block;
  244. line-height: 50rpx;
  245. margin-bottom: 20rpx;
  246. font-size: 26rpx;
  247. }
  248. &.active{
  249. color: #e28d54;
  250. .iconfont{
  251. color: #e28d54;
  252. }
  253. }
  254. }
  255. }
  256. }
  257. </style>