Skip to content

省市联动

本插件最后效果

属性指南

属性名说明类型默认值是否必须
list省市联动地图数据格式类型必须有 code,name 具体看下图便知Array封装好了数据非必须填写
provinceStyle省份样式cssObj-非必须填写
cityStyle城市样式cssObj-非必须填写
streetStyle区样式cssObj-非必须填写
provinceplaceholder省份没输入的时候提示问题string请选择省份非必须填写
cityplaceholder城市没输入的时候提示问题string请选择省份非必须填写
streetplaceholder区域没输入的时候提示问题string请选择省份非必须填写
provincedataprops传入省份数据反显的值{code: string, name: string}-非必须填写
citydataprops传入城市数据反显的值{code: string, name: string}-非必须填写
streetdataprops传入区数据反显的值{code: string, name: string}-非必须填写
getResult获取最后的值方法通过这个方法获取到最后省份城市 区域-必须填写

封装插件

类型

ts
export interface IData {
  code: string;
  name: string;
}

export interface IChooseAreaProps {
  code: string;
  name: string;
  children?: IChooseAreaProps[];
}

export interface IChooseAreaState {
  list?: IChooseAreaProps[];
  provinceStyle?: Object;
  cityStyle?: Object;
  streetStyle?: Object;
  provinceplaceholder?: string;
  cityplaceholder?: string;
  streetplaceholder?: string;
  provincedataprops?: IData;
  citydataprops?: IData;
  streetdataprops?: IData;
}

组件

vue
<!--
 * @Author: jsopy
 * @Date: 2025-02-08 10:05:54
 * @LastEditTime: 2025-02-09 21:14:06
 * @FilePath: /demoall/src/components/chooseArea/src/index.vue
 * @Description: 
 * 
-->
<template>
  <div>
    <!--省份开始-->
    <el-select
      value-key="code"
      v-model="provincedata"
      :placeholder="props.provinceplaceholder"
      :style="props.provinceStyle"
      @change="getDataAll"
    >
      <el-option
        v-for="item in worldoptions"
        :label="item.name"
        :value="item"
      />
    </el-select>
    <!--省份结束-->
    <!--市区开始-->
    <el-select
      @change="getDataAll"
      value-key="code"
      v-model="citydata"
      :placeholder="props.cityplaceholder"
      :style="props.cityStyle"
    >
      <el-option
        v-for="item in cityoptions"
        :key="item.code"
        :label="item.name"
        :value="item"
      />
    </el-select>
    <!--市区结束-->

    <!--街道开始-->
    <el-select
      value-key="code"
      @change="getDataAll"
      v-model="streetdata"
      :placeholder="props.streetplaceholder"
      :style="props.streetStyle"
    >
      <el-option
        v-for="item in streetoptions"
        :key="item.code"
        :label="item.name"
        :value="item"
      />
    </el-select>
    <!--街道结束-->
  </div>
</template>

<script setup lang="ts">
import dataResult from "../lib/data.json";
import { ref, onMounted, watch, type CSSProperties } from "vue";
import { type IChooseAreaProps, type IData } from "@/types/chooseArea/type";

const emits = defineEmits<{
  (e: "getResult", val: IData[]): void;
}>();

const props = withDefaults(
  defineProps<{
    list?: IChooseAreaProps[];
    provinceStyle?: CSSProperties;
    cityStyle?: CSSProperties;
    streetStyle?: CSSProperties;
    provinceplaceholder?: string;
    cityplaceholder?: string;
    streetplaceholder?: string;
    provincedataprops?: IData;
    citydataprops?: IData;
    streetdataprops?: IData;
  }>(),
  {
    list: () => {
      return dataResult;
    },
    provinceStyle: () => {
      return {};
    },
    cityStyle: () => {
      return {};
    },
    streetStyle: () => {
      return {};
    },
    provinceplaceholder: "请选择省份",
    cityplaceholder: "请选择市区",
    streetplaceholder: "请选择街道",
    provincedataprops: () => {
      return {
        code: "",
        name: "",
      };
    },
    citydataprops: () => {
      return {
        code: "",
        name: "",
      };
    },
    streetdataprops: () => {
      return {
        code: "",
        name: "",
      };
    },
  }
);

// 省份
const provincedata = ref<IData>();
// 市区
const citydata = ref<IData>();
// street 街道
const streetdata = ref<IData>();

// 省市区list
const worldoptions = ref<IData[]>([]);

// 获取区list
const cityoptions = ref<IData[]>([]);

// 获取streetlist
const streetoptions = ref<IData[]>([]);

// 省份数据

// 获取市list
const getworldoptions = () => {
  let result: IData[] = [];
  props.list.forEach((item) => {
    let obj = {
      code: item.code,
      name: item.name,
    };
    result.push(obj);
  });
  worldoptions.value = result;
};

// 获取市区
const getcityoptions = () => {
  let result: IData[] = [];
  props.list.forEach((item: IChooseAreaProps, index) => {
    if (item.name === provincedata.value?.name) {
      (item.children as IData[]).forEach((item) => {
        let obj = {
          code: item.code,
          name: item.name,
        };
        result.push(obj);
      });
    }
  });
  cityoptions.value = result;
};

// 定义一个函数,用于获取街道选项
const getstreetoptions = () => {
  // 定义一个空数组,用于存储街道选项
  let result: IData[] = [];
  // 遍历data数组
  props.list.forEach((item: IChooseAreaProps, index: number) => {
    // 如果当前项的name属性等于provincedata.value.name
    if (item.name === provincedata.value?.name) {
      // 遍历当前项的children数组
      (item.children as IData[]).forEach(
        (item: IChooseAreaProps, index: number) => {
          // 如果当前项的name属性等于cityvalue.value
          if (item.name === citydata.value?.name) {
            // 遍历当前项的children数组
            (item.children as IData[]).forEach(
              (item: IChooseAreaProps, index: number) => {
                // 定义一个对象,用于存储街道选项的code和name属性
                let obj = {
                  code: item.code,
                  name: item.name,
                };
                // 将对象添加到result数组中
                result.push(obj);
              }
            );
          }
        }
      );
    }
  });
  // 将result数组赋值给streetoptions.value
  streetoptions.value = result;
};

// 监听省份变化
watch(
  () => provincedata.value?.name,
  (newval, oldval) => {
    if (newval != oldval) {
      if (oldval) {
        citydata.value = { code: "", name: "" };
        streetdata.value = { code: "", name: "" };
      }

      getcityoptions();
      getstreetoptions();
    }
  },
  {
    deep: true,
    immediate: true,
  }
);
// 监听城市变化
watch(
  () => citydata.value?.name,
  (newval, oldval) => {
    if (newval != oldval) {
      if (oldval) {
        streetdata.value = { code: "", name: "" };
      }
      getstreetoptions();
    }
  },
  {
    deep: true,
    immediate: true,
  }
);

// 封装一个方法获取所有的数据

const getDataAll = () => {
  // emits.getResult([provincedata.value, citydata.value, streetdata.value])
  setTimeout(() => {
    emits("getResult", [
      provincedata.value as IData,
      citydata.value as IData,
      streetdata.value as IData,
    ]);
  }, 100);
};

onMounted(() => {
  if (props.provincedataprops.name != "") {
    provincedata.value = JSON.parse(JSON.stringify(props.provincedataprops));
  }

  if (props.citydataprops.name != "") {
    console.log("ceshi");
    citydata.value = JSON.parse(JSON.stringify(props.citydataprops));
  }

  if (props.streetdataprops.name != "") {
    streetdata.value = JSON.parse(JSON.stringify(props.streetdataprops));
  }

  getworldoptions();
});
</script>

<style scoped></style>

调用组件

vue
<template>
  <div class="pagecontent">
    <yj-area
      :provinceStyle="provinceStyle"
      :cityStyle="cityStyle"
      :streetStyle="streetStyle"
      :provinceplaceholder="provinceplaceholder"
      :cityplaceholder="cityplaceholder"
      :streetplaceholder="streetplaceholder"
      :provincedataprops="provincedataprops"
      :citydataprops="citydataprops"
      :streetdataprops="streetdataprops"
      @getResult="getResultAll"
    ></yj-area>

    <yj-area @getResult="getResultAll2"></yj-area>
  </div>
</template>

<script setup lang="ts">
import { type IData } from "@/types/chooseArea/type";
import { ref } from "vue";

const provinceStyle = ref({
  width: "300px",
  marginRight: "10px",
});

const cityStyle = ref({
  width: "200px",
  marginRight: "20px",
});
const streetStyle = ref({
  width: "300px",
  marginRight: "30px",
});
const provinceplaceholder = ref("选择省份");
const cityplaceholder = ref("选择城市");
const streetplaceholder = ref("选择区县");

const provincedataprops = ref({ code: "12", name: "天津市" });
const citydataprops = ref({ code: "1201", name: "市辖区" });
const streetdataprops = ref({ code: "120103", name: "河西区" });
// 获取最后数据的方法
const getResultAll = (content: IData[]) => {
  console.log(content);
};
// 获取最后数据的方法
const getResultAll2 = (content: IData[]) => {
  console.log(content);
};
</script>

<style scoped lang="scss">
.pagecontent {
  height: 100%;
}
</style>