Browse Source

feat: address 新增默认选中功能 (#1035)

* feat: address 新增默认选中功能
yangxiaolu1993 3 years ago
parent
commit
f52993e176

+ 41 - 3
src/packages/__VUE/address/demo.vue

@@ -14,10 +14,27 @@
       custom-address-title="请选择所在地区"
     ></nut-address>
 
+    <h2>选中省市区</h2>
+    <nut-cell title="选择地址" :desc="six" is-link @click="showSelected"></nut-cell>
+
+    <nut-address
+      v-model="value"
+      v-model:visible="select"
+      :province="province"
+      :city="city"
+      :country="country"
+      :town="town"
+      @change="(cal) => onChange(cal, 'select')"
+      @close="close6"
+      custom-address-title="请选择所在地区"
+      :columns-placeholder="placeholder"
+    ></nut-address>
+
     <h2>选择自定义地址2</h2>
     <nut-cell title="选择地址" :desc="five" is-link @click="showAddress2"></nut-cell>
 
     <nut-address
+      v-model="value2"
       v-model:visible="normal2"
       type="custom2"
       :province="province"
@@ -27,6 +44,7 @@
       height="270px"
       @change="(cal) => onChange(cal, 'normal2')"
       @close="close5"
+      :columns-placeholder="placeholder"
       custom-address-title="请选择所在地区"
     ></nut-address>
 
@@ -143,12 +161,17 @@ export default createDemo({
       town: []
     });
 
+    const placeholder = ref(['请选择省', '请选择市', '请选择县']);
+    const value = ref([1, 7, 3]);
+    const value2 = ref([1, 7, 3]);
+
     const showPopup = reactive({
       normal: false,
       normal2: false,
       exist: false,
       customImg: false,
-      other: false
+      other: false,
+      select: false
     });
 
     const icon = reactive({
@@ -199,7 +222,8 @@ export default createDemo({
       two: '请选择地址',
       three: '请选择地址',
       four: '请选择地址',
-      five: '请选择地址'
+      five: '北京朝阳区八里庄街道',
+      six: '北京朝阳区八里庄街道'
     });
 
     const showAddress = () => {
@@ -210,6 +234,10 @@ export default createDemo({
       showPopup.normal2 = !showPopup.normal2;
     };
 
+    const showSelected = () => {
+      showPopup.select = !showPopup.select;
+    };
+
     const onChange = (cal: CalBack, tag: string) => {
       const name = (address as any)[cal.next];
       if (name.length < 1) {
@@ -222,8 +250,13 @@ export default createDemo({
     };
 
     const close5 = (val: CalResult) => {
-      console.log(val);
       text.five = val.data.addressStr;
+      value2.value = [val.data.province.id, val.data.city.id, val.data.country.id];
+    };
+
+    const close6 = (val: CalResult) => {
+      text.six = val.data.addressStr;
+      value.value = [val.data.province.id, val.data.city.id, val.data.country.id];
     };
 
     const showAddressExist = () => {
@@ -284,6 +317,8 @@ export default createDemo({
     };
 
     return {
+      value,
+      value2,
       showAddress,
       showAddress2,
       showPopup,
@@ -292,7 +327,9 @@ export default createDemo({
       showAddressExist,
       close2,
       close5,
+      close6,
       selected,
+      showSelected,
       existAddress,
       showAddressOther,
       showCustomImg,
@@ -300,6 +337,7 @@ export default createDemo({
       close4,
       switchModule,
       closeMask,
+      placeholder,
       ...toRefs(icon),
       ...toRefs(text),
       ...toRefs(showPopup),

+ 76 - 1
src/packages/__VUE/address/doc.md

@@ -90,6 +90,80 @@ app.use(Elevator);
 ```
 :::
 
+### 选择省市区
+
+如果想选中某个省市区,需要在 model-value 中按照 province、city、country、town 的顺序配置想要展示的地区 id 值,并且保证有能查询到对应的省市区数据即可。
+
+:::demo
+```html
+<template>
+<nut-cell title="选择地址" :desc="text" is-link @click="showAddress"></nut-cell>
+<nut-address
+    v-model="value"
+    v-model:visible="showPopup"
+    :province="province"
+    :city="city"
+    :country="country"
+    :town="town"
+    @change="onChange"
+    @close="close"
+    custom-address-title="请选择所在地区"
+    :columns-placeholder="placeholder"
+></nut-address>
+</template>
+<script>
+  import { ref,reactive,toRefs } from 'vue';
+  export default {
+    setup() {
+        const showPopup = ref(false);
+        const address = reactive({
+          province:[
+            { id: 1, name: '北京' },
+            { id: 2, name: '广西' },
+            { id: 3, name: '江西' },
+            { id: 4, name: '四川' }
+          ],
+          city:[
+            { id: 7, name: '朝阳区' },
+            { id: 8, name: '崇文区' },
+            { id: 9, name: '昌平区' },
+            { id: 6, name: '石景山区' }
+          ],
+          country:[
+            { id: 3, name: '八里庄街道' },
+            { id: 9, name: '北苑' },
+            { id: 4, name: '常营乡' }
+          ],
+          town:[]
+        })
+
+        const text = ref('北京朝阳区八里庄街道')
+        const value = ref([1, 7, 3]);
+
+        const showAddress = () => {
+          showPopup.value = !showPopup.value;
+        };
+
+        const onChange = (cal) => {
+          const name = address[cal.next]
+          if (name.length < 1) {
+            showPopup.value = false;
+          }
+        };
+        const close = val => {
+          console.log(val);
+          text.value = val.data.addressStr;
+          value.value = [val.data.province.id, val.data.city.id, val.data.country.id];
+        };
+
+        return { showPopup, text, showAddress, onChange, close, value, ...toRefs(address) };
+    }
+  }
+</script>
+
+```
+:::
+
 ### 选择自定义地址2
 
 :::demo
@@ -136,7 +210,7 @@ app.use(Elevator);
           town:[]
         })
 
-        const text = ref('请选择地址')
+        const text = ref('北京朝阳区八里庄街道')
 
         const showAddress = () => {
           showPopup.value = !showPopup.value;
@@ -473,6 +547,7 @@ app.use(Elevator);
 | custom-address-title  | 自定义地址选择文案,type='custom' 时生效 | String | '请选择所在地区'
 | exist-address-title| 已有地址文案 ,type=‘exist’ 时生效| String | '配送至'
 | custom-and-exist-title| 自定义地址与已有地址切换按钮文案 ,type=‘exist’ 时生效| String | '选择其他地址'
+| columns-placeholder | 列提示文字 | String|Array | '请选择'
 
 
   * provinceName 省的名字

+ 8 - 0
src/packages/__VUE/address/index.scss

@@ -37,6 +37,14 @@
           font-weight: bold;
         }
 
+        view {
+          display: block;
+          max-width: 100px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+
         span {
           display: inline-block;
           max-width: 100px;

+ 77 - 19
src/packages/__VUE/address/index.taro.vue

@@ -5,7 +5,6 @@
     @click-overlay="clickOverlay"
     @open="closeWay = 'self'"
     v-model:visible="showPopup"
-    :class="classes"
   >
     <view class="nut-address">
       <view class="nut-address__header">
@@ -13,7 +12,7 @@
           <nut-icon
             :name="backBtnIcon"
             color="#cccccc"
-            v-if="privateType == 'custom' && type == 'exist' && backBtnIcon"
+            v-show="type == 'exist' && privateType == 'custom' && backBtnIcon"
           ></nut-icon>
         </view>
 
@@ -28,16 +27,14 @@
 
       <!-- 请选择 -->
       <view class="custom-address" v-if="privateType == 'custom'">
-        <view class="region-tab">
+        <view class="region-tab" ref="tabRegion">
           <view
-            class="tab-item"
-            :class="[index == tabIndex ? 'active' : '', key]"
+            :class="{ 'tab-item': true, active: index == tabIndex, [tabName[index]]: true }"
             v-for="(item, key, index) in selectedRegion"
             :key="index"
-            :ref="key"
             @click="changeRegionTab(item, key, index)"
           >
-            <view>{{ getTabName(item, index) }}</view>
+            <view>{{ getTabName(item, index) }} </view>
           </view>
 
           <view class="region-tab-line" ref="regionLine" :style="{ left: lineDistance + 'px' }"></view>
@@ -48,8 +45,7 @@
             <li
               v-for="(item, index) in regionList[tabName[tabIndex]]"
               :key="index"
-              class="region-item"
-              :class="[selectedRegion[tabName[tabIndex]].id == item.id ? 'active' : '']"
+              :class="['region-item', selectedRegion[tabName[tabIndex]].id == item.id ? 'active' : '']"
               @click="nextAreaList(item)"
             >
               <nut-icon
@@ -65,21 +61,20 @@
         </view>
       </view>
 
-      <view class="custom-address" v-else-if="privateType === 'custom2'">
-        <view class="region-tab">
+      <!-- 请选择 -->
+      <view class="custom-address" v-else-if="privateType == 'custom2'">
+        <view class="region-tab" ref="tabRegion">
           <view
-            class="tab-item"
-            :class="[index == tabIndex ? 'active' : '']"
+            :class="{ 'tab-item': true, active: index == tabIndex, [tabName[index]]: true }"
             v-for="(item, key, index) in selectedRegion"
             :key="index"
-            :ref="key"
             @click="changeRegionTab(item, key, index)"
           >
             <view>{{ getTabName(item, index) }}</view>
           </view>
           <view class="region-tab-line" ref="regionLine" :style="{ left: lineDistance + 'px' }"></view>
         </view>
-        <view class="elevator-group" v-if="showPopup">
+        <view class="elevator-group">
           <nut-elevator
             :height="height"
             :index-list="regionList[tabName[tabIndex]]"
@@ -119,7 +114,6 @@
             </li>
           </ul>
         </div>
-
         <div class="choose-other" @click="switchModule" v-if="isShowCustomAddress">
           <div class="btn">{{ customAndExistTitle }}</div>
         </div>
@@ -128,7 +122,7 @@
   </nut-popup>
 </template>
 <script lang="ts">
-import { reactive, ref, toRefs, watch, computed } from 'vue';
+import { reactive, ref, toRefs, watch, computed, onMounted } from 'vue';
 import { createComponent } from '../../utils/create';
 import Taro from '@tarojs/taro';
 
@@ -156,6 +150,10 @@ interface AddressList {
 export default create({
   inheritAttrs: false,
   props: {
+    modelValue: {
+      type: Array,
+      default: () => []
+    },
     visible: {
       type: Boolean,
       default: false
@@ -223,9 +221,13 @@ export default create({
     height: {
       type: [String, Number],
       default: '200px'
+    },
+    columnsPlaceholder: {
+      type: [String, Array],
+      default: '请选择'
     }
   },
-  emits: ['update:visible', 'type', 'change', 'selected', 'close', 'close-mask', 'switch-module'],
+  emits: ['update:visible', 'update:modelValue', 'type', 'change', 'selected', 'close', 'close-mask', 'switch-module'],
 
   setup(props, { emit }) {
     const classes = computed(() => {
@@ -247,6 +249,7 @@ export default create({
     const privateType = ref(props.type);
     const tabIndex = ref(0);
     const tabName = ref(['province', 'city', 'country', 'town']);
+    const tabNameDefault = ref(['']);
 
     const isCustom2 = computed(() => props.type === 'custom2');
 
@@ -306,6 +309,54 @@ export default create({
 
     const lineDistance = ref(20);
 
+    onMounted(() => {
+      customPlaceholder();
+    });
+
+    // 设置选中省市县
+    const initCustomSelected = () => {
+      console.log(props.modelValue);
+      if (props.modelValue.length > 0) {
+        tabIndex.value = props.modelValue.length - 1;
+        for (let index = 0; index < props.modelValue.length; index++) {
+          if ((regionList as any)[tabName.value[index]].length == 0) {
+            tabIndex.value = index - 1;
+            break;
+          } else {
+            const val = props.modelValue[index];
+            const arr: [] = (regionList as any)[tabName.value[index]];
+            if (privateType.value == 'custom') {
+              (selectedRegion as any)[tabName.value[index]] = arr.filter((item: RegionData) => item.id == val)[0];
+            } else if (privateType.value == 'custom2') {
+              let sumArr: any = [];
+              arr.map((item) => {
+                sumArr.push(...(item as any).list);
+              });
+              (selectedRegion as any)[tabName.value[index]] = sumArr.filter((item: RegionData) => item.id == val)[0];
+            }
+          }
+        }
+        lineAnimation();
+      }
+    };
+
+    // 自定义‘请选择’文案
+    const customPlaceholder = () => {
+      let typeD = Object.prototype.toString.call(props.columnsPlaceholder);
+      if (typeD == '[object String]') {
+        tabNameDefault.value = new Array(4).fill(props.columnsPlaceholder);
+      } else if (typeD == '[object Array]') {
+        tabNameDefault.value = new Array(4).fill('');
+        tabNameDefault.value.forEach((val, index) => {
+          if (props.columnsPlaceholder[index]) {
+            tabNameDefault.value[index] = props.columnsPlaceholder[index];
+          } else {
+            tabNameDefault.value[index] = '请选择';
+          }
+        });
+      }
+    };
+
     //获取已选地区列表名称
     const getTabName = (item: RegionData, index: number) => {
       if (item.name) return item.name;
@@ -334,6 +385,7 @@ export default create({
         Taro.createSelectorQuery()
           .selectAll(`.${tabName.value[tabIndex.value]}`)
           .boundingClientRect((rects) => {
+            console.log(rects);
             (rects as any).forEach((rect) => {
               if (rect.width > 0) lineDistance.value = rect.left;
             });
@@ -352,7 +404,10 @@ export default create({
 
       (selectedRegion as any)[tabName.value[tabIndex.value]] = item;
 
-      for (let i = tabIndex.value; i < tabIndex.value - 1; i++) {
+      // for (let i = tabIndex.value; i < tabIndex.value - 1; i++) {
+      //   (selectedRegion as any)[tabName.value[i + 1]] = {};
+      // }
+      for (let i = tabIndex.value; i < 4; i++) {
         (selectedRegion as any)[tabName.value[i + 1]] = {};
       }
 
@@ -367,6 +422,7 @@ export default create({
         emit('change', calBack);
       } else {
         handClose();
+        emit('update:modelValue');
       }
     };
     //切换地区Tab
@@ -480,6 +536,8 @@ export default create({
       (value) => {
         if (value == false) {
           close();
+        } else {
+          initCustomSelected();
         }
       }
     );

+ 66 - 7
src/packages/__VUE/address/index.vue

@@ -35,7 +35,7 @@
             :key="index"
             @click="changeRegionTab(item, key, index)"
           >
-            <view>{{ getTabName(item, index) }}</view>
+            <view>{{ getTabName(item, index) }} </view>
           </view>
 
           <view class="region-tab-line" ref="regionLine" :style="{ left: lineDistance + 'px' }"></view>
@@ -125,7 +125,7 @@
   </nut-popup>
 </template>
 <script lang="ts">
-import { reactive, ref, toRefs, watch, nextTick, computed, Ref } from 'vue';
+import { reactive, ref, toRefs, watch, nextTick, computed, Ref, onMounted } from 'vue';
 import { createComponent } from '../../utils/create';
 const { componentName, create } = createComponent('address');
 interface RegionData {
@@ -149,6 +149,10 @@ interface AddressList {
 export default create({
   inheritAttrs: false,
   props: {
+    modelValue: {
+      type: Array,
+      default: () => []
+    },
     visible: {
       type: Boolean,
       default: false
@@ -216,9 +220,13 @@ export default create({
     height: {
       type: [String, Number],
       default: '200px'
+    },
+    columnsPlaceholder: {
+      type: [String, Array],
+      default: '请选择'
     }
   },
-  emits: ['update:visible', 'type', 'change', 'selected', 'close', 'close-mask', 'switch-module'],
+  emits: ['update:visible', 'update:modelValue', 'type', 'change', 'selected', 'close', 'close-mask', 'switch-module'],
 
   setup(props: any, { emit }) {
     const regionLine = ref<null | HTMLElement>(null);
@@ -229,6 +237,7 @@ export default create({
     const privateType = ref(props.type);
     const tabIndex = ref(0);
     const tabName = ref(['province', 'city', 'country', 'town']);
+    const tabNameDefault = ref(['']);
 
     const isCustom2 = computed(() => props.type === 'custom2');
 
@@ -288,6 +297,52 @@ export default create({
 
     const lineDistance = ref(20);
 
+    onMounted(() => {
+      customPlaceholder();
+    });
+
+    // 设置选中省市县
+    const initCustomSelected = () => {
+      if (props.modelValue.length > 0) {
+        tabIndex.value = props.modelValue.length - 1;
+        for (let index = 0; index < props.modelValue.length; index++) {
+          if ((regionList as any)[tabName.value[index]].length == 0) {
+            tabIndex.value = index - 1;
+            break;
+          } else {
+            const val = props.modelValue[index];
+            const arr: [] = (regionList as any)[tabName.value[index]];
+            if (privateType.value == 'custom') {
+              (selectedRegion as any)[tabName.value[index]] = arr.filter((item: RegionData) => item.id == val)[0];
+            } else if (privateType.value == 'custom2') {
+              let sumArr: any = [];
+              arr.map((item) => {
+                sumArr.push(...(item as any).list);
+              });
+              (selectedRegion as any)[tabName.value[index]] = sumArr.filter((item: RegionData) => item.id == val)[0];
+            }
+          }
+        }
+        lineAnimation();
+      }
+    };
+    // 自定义‘请选择’文案
+    const customPlaceholder = () => {
+      let typeD = Object.prototype.toString.call(props.columnsPlaceholder);
+      if (typeD == '[object String]') {
+        tabNameDefault.value = new Array(4).fill(props.columnsPlaceholder);
+      } else if (typeD == '[object Array]') {
+        tabNameDefault.value = new Array(4).fill('');
+        tabNameDefault.value.forEach((val, index) => {
+          if (props.columnsPlaceholder[index]) {
+            tabNameDefault.value[index] = props.columnsPlaceholder[index];
+          } else {
+            tabNameDefault.value[index] = '请选择';
+          }
+        });
+      }
+    };
+
     //获取已选地区列表名称
     const getTabName = (item: RegionData, index: number) => {
       if (item.name) return item.name;
@@ -295,7 +350,7 @@ export default create({
       if (tabIndex.value < index) {
         return item.name;
       } else {
-        return '请选择';
+        return tabNameDefault.value[index];
       }
     };
     // 手动关闭 点击叉号(cross),或者蒙层(mask)
@@ -312,8 +367,6 @@ export default create({
     };
     // 移动下面的红线
     const lineAnimation = () => {
-      // console.log('滑动红线');
-
       nextTick(() => {
         const name = tabRegion.value && tabRegion.value.getElementsByClassName('active')[0];
 
@@ -334,8 +387,11 @@ export default create({
       };
 
       (selectedRegion as any)[tabName.value[tabIndex.value]] = item;
+      // for (let i = tabIndex.value; i < tabIndex.value - 1; i++) {
+      //   (selectedRegion as any)[tabName.value[i + 1]] = {};
+      // }
 
-      for (let i = tabIndex.value; i < tabIndex.value - 1; i++) {
+      for (let i = tabIndex.value; i < 4; i++) {
         (selectedRegion as any)[tabName.value[i + 1]] = {};
       }
 
@@ -350,6 +406,7 @@ export default create({
         emit('change', calBack);
       } else {
         handClose();
+        emit('update:modelValue');
       }
     };
     //切换地区Tab
@@ -463,6 +520,8 @@ export default create({
       (value) => {
         if (value == false) {
           close();
+        } else {
+          initCustomSelected();
         }
       }
     );

+ 2 - 2
src/sites/mobile-taro/vue/project.private.config.json

@@ -13,8 +13,8 @@
     "miniprogram": {
       "list": [
         {
-          "name": "business/pages/barrage/index",
-          "pathName": "business/pages/barrage/index",
+          "name": "business/pages/address/index",
+          "pathName": "business/pages/address/index",
           "query": "",
           "scene": null
         },

+ 42 - 3
src/sites/mobile-taro/vue/src/business/pages/address/index.vue

@@ -14,10 +14,27 @@
       custom-address-title="请选择所在地区"
     ></nut-address>
 
+    <h2>选中省市区</h2>
+    <nut-cell title="选择地址" :desc="six" is-link @click="showSelected"></nut-cell>
+
+    <nut-address
+      v-model="value"
+      v-model:visible="select"
+      :province="province"
+      :city="city"
+      :country="country"
+      :town="town"
+      @change="(cal) => onChange(cal, 'select')"
+      @close="close6"
+      custom-address-title="请选择所在地区"
+      :columns-placeholder="placeholder"
+    ></nut-address>
+
     <h2>选择自定义地址2</h2>
     <nut-cell title="选择地址" :desc="five" is-link @click="showAddress2"></nut-cell>
 
     <nut-address
+      v-model="value2"
       v-model:visible="normal2"
       type="custom2"
       :province="province"
@@ -27,6 +44,7 @@
       height="270px"
       @change="(cal) => onChange(cal, 'normal2')"
       @close="close5"
+      :columns-placeholder="placeholder"
       custom-address-title="请选择所在地区"
     ></nut-address>
 
@@ -129,6 +147,7 @@ export default defineComponent({
         { id: 7, name: '朝阳区', title: 'C' },
         { id: 8, name: '崇文区', title: 'C' },
         { id: 9, name: '昌平区', title: 'C' },
+
         { id: 6, name: '石景山区', title: 'S' },
         { id: 3, name: '八里庄街道', title: 'B' },
         { id: 9, name: '北苑', title: 'B' }
@@ -141,12 +160,17 @@ export default defineComponent({
       town: []
     });
 
+    const placeholder = ref(['请选择省', '请选择市', '请选择县']);
+    const value = ref([1, 7, 3]);
+    const value2 = ref([1, 7, 3]);
+
     const showPopup = reactive({
       normal: false,
       normal2: false,
       exist: false,
       customImg: false,
-      other: false
+      other: false,
+      select: false
     });
 
     const icon = reactive({
@@ -197,7 +221,8 @@ export default defineComponent({
       two: '请选择地址',
       three: '请选择地址',
       four: '请选择地址',
-      five: '请选择地址'
+      five: '请选择地址',
+      six: '请选择地址'
     });
 
     const showAddress = () => {
@@ -208,6 +233,10 @@ export default defineComponent({
       showPopup.normal2 = !showPopup.normal2;
     };
 
+    const showSelected = () => {
+      showPopup.select = !showPopup.select;
+    };
+
     const onChange = (cal: CalBack, tag: string) => {
       const name = (address as any)[cal.next];
       if (name.length < 1) {
@@ -220,8 +249,13 @@ export default defineComponent({
     };
 
     const close5 = (val: CalResult) => {
-      console.log(val);
       text.five = val.data.addressStr;
+      value2.value = [val.data.province.id, val.data.city.id, val.data.country.id];
+    };
+
+    const close6 = (val: CalResult) => {
+      text.six = val.data.addressStr;
+      value.value = [val.data.province.id, val.data.city.id, val.data.country.id];
     };
 
     const showAddressExist = () => {
@@ -282,6 +316,8 @@ export default defineComponent({
     };
 
     return {
+      value,
+      value2,
       showAddress,
       showAddress2,
       showPopup,
@@ -290,7 +326,9 @@ export default defineComponent({
       showAddressExist,
       close2,
       close5,
+      close6,
       selected,
+      showSelected,
       existAddress,
       showAddressOther,
       showCustomImg,
@@ -298,6 +336,7 @@ export default defineComponent({
       close4,
       switchModule,
       closeMask,
+      placeholder,
       ...toRefs(icon),
       ...toRefs(text),
       ...toRefs(showPopup),