高效便捷的省市区选择——Area省市区选择封装实战攻略

前言

省市区选择是许多移动端应用中常见的功能需求,而 vantarea 组件已经为我们提供了一个非常好用的选择方案。但是,在某些场景下,我们需要对 area 进行二次封装,更加定制化的省市区选择功能,以满足更加具体的业务需求。本文将会向大家介绍如何在 vant 中对 area 进行二次封装,并提供一些实用的封装技巧和方法,帮助大家实现更加完美的省市区选择方案。


实现思路

  1. 首先定义一个子组件页面用来封装选择器;
  2. 在父组件中(使用的页面)引入封装组件(子组件)并注册,然后在页面中使用,在父组件中给标签(注册的组件名)上绑定多个属性, 属性上挂载需要传递的值,通过 props 在子组件(封装文件)接收数据;
  3. 在子组件中自定义确定的事件,调用这个事件后,子组件通过 this.$emit('自定义事件名',要传递的数据) 发送父组件可以监听的数据,最后父组件监听子组件事件,调用事件并接收传递过来的数据。

安装

vant 官方提供了一份默认的省市区数据,可以通过 @vant/area-data 引入:

npm i @vant/area-data

定义的参数

参数 描述
selectValue 绑定值 model
keyValue 绑定的 key 字段
columnsNum 绑定的 value 字段
rules 绑定的 option 数据源
required 是否显示红色 * 校验

封装文件

<template>
  <div>
    <van-field v-model="textValue" v-bind="$attrs" :name="$attrs.name" :placeholder="placeholder" :rules="rules" :required="required"
      :readonly="readonly" :is-link="islink" @click="show = !show" />
    <van-popup v-model="show" position="bottom" :overlay="true" :close-on-click-overlay="true">
      <van-area :area-list="areaList" :columns-num="columnsNum" :columns-placeholder="columnsplaceholder" @confirm="onConfirm"
        @cancel="show = !show" />
    </van-popup>
  </div>
</template>

<script>
import {
      
       areaList } from "@vant/area-data";
export default {
      
      
  props: {
      
      
    required: {
      
      
      type: Boolean,
    },
    readonly: {
      
      
      type: Boolean,
    },
    islink: {
      
      
      type: Boolean,
    },
    columnsNum: {
      
      
      type: Number,
    },
    rules: {
      
      
      type: Array,
    },
    selectValue: {
      
      
      type: String,
    },
    keyValue: {
      
      
      //code 返回区县码  name 返回区县名称
      type: String,
    },
  },
  data() {
      
      
    return {
      
      
      areaList,
      show: false,
      textValue: "",
      selectOptions: [],
      placeholder: "",
      columnsplaceholder: ["请选择", "请选择", "请选择"],
      provinceList: null,
      cityList: null,
      countyList: null,
      province: "", //省
      city: "", //市
      county: "", //区县
    };
  },
  methods: {
      
      
    onConfirm(areaData) {
      
      
      // 判断打开选择器后是否必填省/市/区
      if (this.columnsNum == "1") {
      
      
        this.provinceOn(areaData);
      } else if (this.columnsNum == "2") {
      
      
        this.provinceCityOn(areaData);
      } else {
      
      
        this.provincesMunicipalitiesOn(areaData);
      }
    },
    // 省时必填校验
    provinceOn(areaData) {
      
      
      let province = areaData[0];
      if (province.name) {
      
      
      } else {
      
      
        this.$toast("请选择省");
        return;
      }
      this.acquireOn(areaData);
    },
    // 省市时必填校验
    provinceCityOn(areaData) {
      
      
      let province = areaData[0];
      let city = areaData[1];
      if (province.name) {
      
      
      } else {
      
      
        this.$toast("请选择省");
        return;
      }
      if (city.name) {
      
      
      } else {
      
      
        this.$toast("请选择市");
        return;
      }
      this.acquireOn(areaData);
    },
    // 省市区时必填校验
    provincesMunicipalitiesOn(areaData) {
      
      
      let province = areaData[0];
      let city = areaData[1];
      let area = areaData[2];
      if (province.name) {
      
      
      } else {
      
      
        this.$toast("请选择省");
        return;
      }
      if (city.name) {
      
      
      } else {
      
      
        this.$toast("请选择市");
        return;
      }
      if (area.name) {
      
      
      } else {
      
      
        this.$toast("请选择区");
        return;
      }
      this.acquireOn(areaData);
    },
    // 校验完后执行确定方法赋值name/code
    acquireOn(areaData) {
      
      
      // 获取选中name/code值
      let names = "";
      let codes = "";
      areaData.map((item, index) => {
      
      
        if (!item) {
      
      
          return "";
        }
        if (index > 0) {
      
      
          names += "/" + item.name;
          codes += "/" + item.code;
        } else {
      
      
          names += item.name;
          codes += item.code;
        }
      });
      if (this.keyValue == "code") {
      
      
        this.textValue = codes;
      } else {
      
      
        this.textValue = names;
      }
      this.show = !this.show;
      this.$emit("confirm", this.textValue);
    },
    //通过code 值获取地区name
    getNameByCode(value, list) {
      
      
      let name = "";
      if (!value) {
      
      
        return;
      }
      Object.keys(list).forEach((key) => {
      
      
        if (value.toString() == key.toString()) {
      
      
          name = list[key];
        }
      });
      return name;
    },
    //地区回显
    getValue(type) {
      
      
      if (!this.selectValue || !this.selectValue.length) {
      
      
        //如果 value传值不存在
        this.textValue = "";
        return;
      }
      let selectList = this.selectValue.split("/");
      let provinceName,
        cityName,
        countyName = "";
      switch (type) {
      
      
        case "code":
          //如果父级传值是 code
          if (Number(this.columnsNum) == 1) {
      
      
            //省
            provinceName = this.getNameByCode(selectList[0], this.provinceList);
            this.textValue = provinceName;
          } else if (Number(this.columnsNum) == 2) {
      
      
            //省
            provinceName = this.getNameByCode(selectList[0], this.provinceList);
            //市
            cityName = this.getNameByCode(selectList[1], this.cityList);
            this.textValue = provinceName + "/" + cityName;
          } else {
      
      
            //省
            provinceName = this.getNameByCode(selectList[0], this.provinceList);
            //市
            cityName = this.getNameByCode(selectList[1], this.cityList);
            //区
            countyName = this.getNameByCode(selectList[2], this.countyList);
            this.textValue = provinceName + "/" + cityName + "/" + countyName;
          }
          break;
        case "name":
          //如果父级传值是 name
          this.textValue = this.selectValue;
          break;
      }
    },
  },
  watch: {
      
      
    // json数据
    areaList: {
      
      
      handler(newVal) {
      
      
        if (newVal) {
      
      
          let length = Object.keys(newVal).length;
          if (length) {
      
      
            this.cityList = newVal.city_list;
            this.countyList = newVal.county_list;
            this.provinceList = newVal.province_list;
          }
        }
      },
      immediate: true,
      deep: true,
    },
    // 控制选择完整省市区还是部分
    columnsNum: {
      
      
      handler(newVal) {
      
      
        switch (newVal) {
      
      
          case 1:
            this.placeholder = "省";
            this.columnsplaceholder = ["请选择"];
            break;
          case 2:
            this.placeholder = "省/市";
            this.columnsplaceholder = ["请选择", "请选择"];
            break;
          default:
            this.placeholder = "省/市/区";
            this.columnsplaceholder = ["请选择", "请选择", "请选择"];
        }
      },
      immediate: true,
    },
    selectValue: {
      
      
      handler(newValue) {
      
      
        this.$nextTick(() => {
      
      
          if (this.keyValue) {
      
      
            this.getValue(this.keyValue);
          }
        });
      },
      immediate: true,
    },
    keyValue: {
      
      
      handler(newValue) {
      
      
        if (newValue) {
      
      
          this.getValue(newValue);
        }
      },
      immediate: true,
    },
  },
};
</script>

使用文件

<template>
  <div>
    <van-form validate-first>
      <AreaSelect name="cjPovo" label="车辆注册地" :selectValue="cjPovo" :readonly="true" :keyValue="`name`" :columnsNum="3"
        @confirm="areaConfirm" :required="true" :rules="rules.cjPovo" />
      <div class="btnBomBox">
        <van-button round size="small" block @click="submitOn" type="info">提交</van-button>
      </div>
    </van-form>
  </div>
</template>

<script>
import AreaSelect from "@/components/areaSelect/index";
export default {
      
      
  components: {
      
      
    AreaSelect,
  },
  data() {
      
      
    return {
      
      
      cjPovo: "",
      rules: {
      
      
        cjPovo: [
          {
      
      
            required: true,
            message: "请选择车辆注册地",
          },
        ],
      },
    };
  },
  methods: {
      
      
    // 点击确定
    areaConfirm(data) {
      
      
      this.cjPovo = data;
    },
    // 提交
    submitOn() {
      
      
      console.log(this.cjPovo);
    },
  },
};
</script>

<style scoped>
.btnBomBox {
      
      
  padding: 0px 16px;
  display: flex;
  justify-content: center;
}
</style>

实现效果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Shids_/article/details/131087972