请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

使用v-modal,双向绑定省市区选择器?

老师,你好
如何使用v-modal,双向绑定省市区选择器?
下面代码虽然能实现此功能,但感觉不太优雅,要使用 setTimeout + watch 去一级一级的控制下拉框列表数据的渲染,请问老师有更好的方法、思路吗?多谢多谢~~

<template>
  <div class="area-choose jiang-select-margin">
    <el-select v-model="province" placeholder="请选择省份" clearable>
      <el-option
        v-for="item in provinceList"
        :key="item.code"
        :value="item.code"
        :label="item.name"
      >
      </el-option>
    </el-select>
    <el-select
      v-model="city"
      placeholder="请选择城市"
      :disabled="!province"
      clearable
    >
      <el-option
        v-for="item in cityList"
        :key="item.code"
        :value="item.code"
        :label="item.name"
      ></el-option>
    </el-select>
    <el-select
      v-model="area"
      placeholder="请选择区域"
      :disabled="!province || !city"
      clearable
    >
      <el-option
        v-for="item in areaList"
        :key="item.code"
        :value="item.code"
        :label="item.name"
      >
      </el-option>
    </el-select>
    <el-select
      v-model="street"
      placeholder="请选择街道"
      :disabled="!province || !city || !area"
      clearable
    >
      <el-option
        v-for="item in streetList"
        :key="item.code"
        :value="item.code"
        :label="item.name"
      >
      </el-option>
    </el-select>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, watch, PropType } from "vue";
import pacsCode from "china-division/dist/pcas-code.json";

export interface AreaItem {
  name: string;
  code: string;
  children?: AreaItem[];
}
export interface addressProps {
  province: AreaItem;
  city: AreaItem;
  area: AreaItem;
  street: AreaItem;
}
export default defineComponent({
  name: "area-choose",
  emits: ["update:address"],
  props: {
    address: {
      type: Object as PropType<addressProps>,
      required: true,
    },
  },
  setup(props, { emit }) {
    const provinceList = ref(pacsCode);
    const province = ref("");
    const city = ref("");
    const area = ref("");
    const street = ref("");
    const cityList = ref<AreaItem[]>([]);
    const areaList = ref<AreaItem[]>([]);
    const streetList = ref<AreaItem[]>([]);
    watch(
      () => props.address,
      async (val) => {
        if (val) {
          province.value = props.address?.province.code;
          setTimeout(() => {
            city.value = props.address.city.code;
          }, 0);
          setTimeout(() => {
            area.value = props.address.area.code;
          }, 0);
          setTimeout(() => {
            street.value = props.address.street.code;
          }, 0);
        }
      },
      {
        immediate: true,
      }
    );
    watch(
      () => province.value,
      (val) => {
        if (val) {
          let cities = provinceList.value.find(
            (item) => item.code === val
          )?.children;
          if (cities) {
            cityList.value = cities;
          }
        }
        city.value = "";
        area.value = "";
        street.value = "";
      },
      {
        immediate: true,
      }
    );
    watch(
      () => city.value,
      (val) => {
        console.log("city.value", val);

        if (val) {
          let areas = cityList.value.find(
            (item) => item.code === val
          )?.children;
          if (areas) {
            areaList.value = areas;
          }
        }
        area.value = "";
        street.value = "";
      },
      {
        immediate: true,
      }
    );
    watch(
      () => area.value,
      (val) => {
        if (val) {
          let streets = areaList.value.find(
            (item) => item.code === val
          )?.children;
          if (streets) {
            console.log(streets);
            streetList.value = streets;
          }
        }
        street.value = "";
      },
      {
        immediate: true,
      }
    );
    watch(
      () => street.value,
      (val) => {
        console.log(val);
        if (val) {
          let selectedProvince = {
            code: province.value,
            name: provinceList.value.find(
              (item) => item.code === province.value
            )?.name,
          };
          let selectedCity = {
            code: city.value,
            name: cityList.value.find((item) => item.code === city.value)?.name,
          };
          let selectedArea = {
            code: area.value,
            name: areaList.value.find((item) => item.code === area.value)?.name,
          };
          let selectedStreet = {
            code: val,
            name: streetList.value.find((item) => item.code === val)?.name,
          };
          emit("update:address", {
            province: selectedProvince,
            city: selectedCity,
            area: selectedArea,
            street: selectedStreet,
          });
        }
      }
    );
    return {
      province,
      city,
      area,
      street,
      provinceList,
      cityList,
      areaList,
      streetList,
    };
  },
});
</script>
<style scoped lang="less"></style>

正在回答 回答被采纳积分+3

2回答

五月的夏天 2021-12-14 17:51:52

这个组件不太建议v-model用法哈,这样会增加用户的心智负担和自己编码的难度 。

0 回复 有任何疑惑可以回复我~
五月的夏天 2021-12-13 18:36:18

不需要定时器啊,课程里面用的方法应该就是最优的,可以参考课程内容 。

0 回复 有任何疑惑可以回复我~
  • 提问者 爱学兮的小江江 #1
    老师,你好。课程中的省市区选择器没有做双向绑定,数据是单向的,子组件通过emit来向父组件传递选中的省市区。
    回复 有任何疑惑可以回复我~ 2021-12-14 10:28:20
  • 你的意思是要从父组件传个值过来吗?
    回复 有任何疑惑可以回复我~ 2021-12-14 10:37:51
  • 有几个问题我没明白,为什么第一个watch里面需要用定时器,是获取不到值吗?可以加deep:true深度监听试一下。并且这个组件设计的时候为什么没有设计成v-model的形式,是因为整体传值会比较复杂,造成使用时的心智负担。
    回复 有任何疑惑可以回复我~ 2021-12-14 12:22:56
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信