前言: 在任何项目中, 组件封装是很常见的, 其中单一项目的的公共组件, 这里记录一个任意项目拿来直接改改样式就可以用的省市区三级联动万能项目组件
<script lang="ts" setup name="XtxCity">
import { onClickOutside } from '@vueuse/core';
import axios from 'axios';
import { reactive, ref } from 'vue';
type areaList = {
code: string;
level: number;
name: string;
areaList: areaList[]
}
// 'https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.json'
let cityList = ref<areaList[]>([])
let cacheList = ref<areaList[]>([])
const getCityList = async () => {
const res = await axios.get('https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.json')
console.log(res)
cityList.value = res.data
cacheList.value = res.data
}
getCityList()
const target = ref(null)
onClickOutside(target, () => {
active.value = false
})
defineProps<{
userAddress?: string
}>()
const emit = defineEmits<{
(event: 'changeCity', val: {
provinceCode: string;
provinceName: string;
cityCode: string;
cityName: string;
countyCode: string;
countyName: string;
}): void
}>()
const active = ref(false)
const toggle = () => {
active.value = !active.value
}
const changeResult = ref({
provinceCode: '',
provinceName: '',
cityCode: '',
cityName: '',
countyCode: '',
countyName: ''
})
const selectCity = (obj: areaList) => {
if (obj.level === 0) {
changeResult.value.provinceName = obj.name
changeResult.value.provinceCode = obj.code
cityList.value = obj.areaList
}
if (obj.level === 1) {
changeResult.value.cityName = obj.name
changeResult.value.cityCode = obj.code
cityList.value = obj.areaList
}
if (obj.level === 2) {
changeResult.value.countyName = obj.name
changeResult.value.countyCode = obj.code
// cityList.value = obj.areaList
// active.value = false
}
if (!obj.areaList) {
active.value = false
cityList.value = cacheList.value
emit('changeCity', changeResult.value)
}
}
watchEffect(() => {
if (!active.value) {
cityList.value = cacheList.value
}
})
</script>
<template>
<div class="xtx-city" ref="target">
<div class="select" @click="toggle" :class="{ active: active }">
<span class="value" v-if="userAddress">{{ userAddress }}</span>
<span class="placeholder" v-else>请选择配送地址</span>
<span class="value"></span>
<i class="iconfont icon-angle-down"></i>
</div>
<div class="option" v-show="active">
<span class="ellipsis" @click="selectCity(item)" v-for="item in cityList" :key="item.code">
{{ item.name }}
</span>
</div>
</div>
</template>
<style scoped lang="less">
.xtx-city {
display: inline-block;
position: relative;
z-index: 400;
.select {
border: 1px solid #e4e4e4;
height: 30px;
padding: 0 5px;
line-height: 28px;
cursor: pointer;
&.active {
background: #fff;
}
.placeholder {
color: #999;
}
.value {
color: #666;
font-size: 12px;
}
i {
font-size: 12px;
margin-left: 5px;
}
}
.option {
width: 542px;
border: 1px solid #e4e4e4;
position: absolute;
left: 0;
top: 29px;
background: #fff;
min-height: 30px;
line-height: 30px;
display: flex;
flex-wrap: wrap;
padding: 10px;
> span {
width: 130px;
text-align: center;
cursor: pointer;
border-radius: 4px;
padding: 0 3px;
&:hover {
background: #f5f5f5;
}
}
}
}
</style>