Skip to content

省市联动

架构

bash
├── src
   ├── components
   ├── chooseArea
      ├── lib (引入的第三方库)
    └── xxx.json
      ├── src (源码)
   ├── index.vue
      ├── index.ts

index.ts

ts
import { type App } from 'vue'
import chooseArea from './src/index.vue'

// 让这个组件可以通过use的形式使用
export default {
    install(app: App) {
        app.component('YJ-choose-area', chooseArea)
    }
}

interface/chooseArea/type.ts

ts
export interface ChooseAreaType {
    code: string
    name: string
}

hooks/choosearea/useChoosearea.ts

ts
import { ref, onMounted, computed, watchEffect, watch } from 'vue'
import data from '@/components/chooseArea/lib/pca-code.json'
import { type ChooseAreaType } from '@/interfaces/chooseArea/type.ts'
export const useChoosearea = () => {
    // 省份
    const worldvalue = ref('')
    // 市
    const cityvalue = ref('')
    // 区
    const streetvalue = ref('')

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

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

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

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

    // 获取区list

    const getcityoptions = () => {
        let result: ChooseAreaType[] = []
        data.forEach(item => {
            if (item.name === worldvalue.value) {
                item.children.forEach(item => {
                    let obj = {
                        code: item.code,
                        name: item.name
                    }
                    result.push(obj)
                })
            }
        })
        cityoptions.value = result
    }

    // 获取街道list

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

    // 监听省份变化
    watch(
        () => worldvalue.value,
        (newval, oldval) => {
            if (newval != oldval) {
                cityvalue.value = ''
                streetvalue.value = ''
                getcityoptions()
                getstreetoptions()
            }
        }
    )
    // 监听城市变化
    watch(
        () => cityvalue.value,
        (newval, oldval) => {
            if (newval != oldval) {
                streetvalue.value = ''
                getstreetoptions()
            }
        }
    )

    // 挂载 筛选出省份
    onMounted(() => {
        getworldoptions()
    })
    return {
        worldvalue,
        cityvalue,
        streetvalue,
        worldoptions,
        cityoptions,
        streetoptions
    }
}

src/index.vue

vue
<template>
    <div>
        <el-select
            filterable
            v-model="worldvalue"
            clearable
            placeholder="请选择省"
            style="width: 240px; margin-right: 20px"
        >
            <el-option v-for="item in worldoptions" :key="item.code" :label="item.name" :value="item.name" />
        </el-select>
        <el-select
            filterable
            v-model="cityvalue"
            clearable
            placeholder="请选择市"
            style="width: 240px; margin-right: 20px"
        >
            <el-option v-for="item in cityoptions" :key="item.code" :label="item.name" :value="item.name" />
        </el-select>
        <el-select
            filterable
            v-model="streetvalue"
            clearable
            placeholder="请选择区"
            style="width: 240px; margin-right: 20px"
        >
            <el-option v-for="item in streetoptions" :key="item.code" :label="item.name" :value="item.name" />
        </el-select>
    </div>
</template>

<script setup lang="ts">
    import { useChoosearea } from '@/hooks/choosearea/useChoosearea.ts'
    const { worldoptions, worldvalue, cityoptions, cityvalue, streetoptions, streetvalue } = useChoosearea()
</script>

<style scoped></style>

父元素调用

vue
<template>
    <div>
        <YJ-choose-area></YJ-choose-area>
    </div>
</template>

<script setup lang="ts"></script>

<style scoped></style>