<template>
<div class="xtx-city" ref="target">
<div class="select" @click="toggle" :class="{active:isShow}">
<span v-if='!fullLocation' class="placeholder">请选择配送地址</span>
<span v-else class="value">{{fullLocation}}</span>
<i class="iconfont icon-angle-down"></i>
</div>
<div class="option" v-show='isShow'>
<div class="loading" v-if="loading"></div>
<template v-else>
<span @click="changeCity(item)" class="ellipsis" v-for="item in cityList" :key="item.code">{{item.name}}</span>
</template>
</div>
</div>
</template>
<script>
import { ref, computed, reactive } from 'vue'
import { onClickOutside } from '@vueuse/core'
import { getCityList } from '@/api/product.js'
export default {
name: 'XtxCity',
props: {
fullLocation: {
type: String,
default: ''
}
},
setup(props, { emit }) {
const isShow = ref(false)
const loading = ref(false)
const toggle = () => {
isShow.value = !isShow.value
if (isShow.value) {
loading.value = true
for (const key in changeResult) {
changeResult[key] = ''
}
getCityList().then(ret => {
list.value = ret
loading.value = false
})
}
}
const target = ref(null)
onClickOutside(target, () => {
isShow.value = false
})
const list = ref([])
const changeResult = reactive({
provinceCode: '',
provinceName: '',
cityCode: '',
cityName: '',
countyCode: '',
countyName: '',
fullLocation: ''
})
const changeCity = city => {
if (city.level === 0) {
changeResult.provinceCode = city.code
changeResult.provinceName = city.name
} else if (city.level === 1) {
changeResult.cityCode = city.code
changeResult.cityName = city.name
} else if (city.level === 2) {
changeResult.countyCode = city.code
changeResult.countyName = city.name
changeResult.fullLocation = `${changeResult.provinceName}${changeResult.cityName}${changeResult.countyName}`
isShow.value = false
emit('change-city', changeResult)
}
}
const cityList = computed(() => {
let result = list.value
if (changeResult.provinceCode && changeResult.provinceName) {
result = result.find(item => item.code === changeResult.provinceCode).areaList
}
if (changeResult.cityCode && changeResult.cityName) {
result = result.find(item => item.code === changeResult.cityCode).areaList
}
return result
})
return { isShow, toggle, target, cityList, loading, changeCity }
}
}
</script>
<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;
.loading {
height: 290px;
width: 100%;
background: url(../../assets/images/loading.gif) no-repeat center;
}
> span {
width: 130px;
text-align: center;
cursor: pointer;
border-radius: 4px;
padding: 0 3px;
&:hover {
background: #f5f5f5;
}
}
}
}
</style>
省市镇获取接口
const cityURL = 'https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.json'
/ 获取省市区列表数据
export const getCityList = async () => {
if (window.cityList) {
return window.cityList
}
const ret = await axios.get(cityURL)
if (ret.data) {
window.cityList = ret.data
}
return ret.data
}
在父组件中使用
<template>
<p class="g-name">{{goods.name}}</p>
<p class="g-desc">{{goods.desc}}</p>
<p class="g-price">
<span>{{goods.price}}</span>
<span>{{goods.oldPrice}}</span>
</p>
<div class="g-service">
<dl>
<dt>促销</dt>
<dd>12月好物放送,App领券购买直降120元</dd>
</dl>
<dl>
<dt>配送</dt>
<dd>至 </dd>
<dd>
<XtxCity @change-city='changeCity' :fullLocation='fullLocation' />
</dd>
</dl>
<dl>
<dt>服务</dt>
<dd>
<span>无忧退货</span>
<span>快速退款</span>
<span>免费包邮</span>
<a href="javascript:;">了解详情</a>
</dd>
</dl>
</div>
</template>
<script>
import { toRef, ref } from 'vue'
export default {
name: 'GoodName',
props: {
goods: {
type: Object,
default: () => {}
}
},
setup(props) {
const goods = toRef(props, 'goods')
const provinceCode = ref('110000')
const cityCode = ref('119900')
const countyCode = ref('110101')
const fullLocation = ref('北京市 市辖区 东城区')
if (goods.value.userAddresses && goods.value.userAddresses.value.length) {
const defaultAddress = goods.value.userAddresses.value.find(item => item.isDefault === 1)
if (defaultAddress) {
provinceCode.value = defaultAddress.provinceCode
cityCode.value = defaultAddress.cityCode
countyCode.value = defaultAddress.countyCode
fullLocation.value = defaultAddress.fullLocation
} else {
provinceCode.value = goods.value.userAddresses.value[0].provinceCode
cityCode.value = goods.value.userAddresses.value[0].cityCode
countyCode.value = goods.value.userAddresses.value[0].countyCode
fullLocation.value = goods.value.userAddresses.value[0].fullLocation
}
}
const changeCity = cityInfo => {
provinceCode.value = cityInfo.provinceCode
cityCode.value = cityInfo.cityCode
countyCode.value = cityInfo.countyCode
fullLocation.value = cityInfo.fullLocation
}
return { fullLocation, changeCity }
}
}
</script>
<style lang="less" scoped>
.g-name {
font-size: 22px;
}
.g-desc {
color: #999;
margin-top: 10px;
}
.g-price {
margin-top: 10px;
span {
&::before {
content: '¥';
font-size: 14px;
}
&:first-child {
color: @priceColor;
margin-right: 10px;
font-size: 22px;
}
&:last-child {
color: #999;
text-decoration: line-through;
font-size: 16px;
}
}
}
.g-service {
background: #f5f5f5;
width: 500px;
padding: 20px 10px 0 10px;
margin-top: 10px;
dl {
padding-bottom: 20px;
display: flex;
align-items: center;
dt {
width: 50px;
color: #999;
}
dd {
color: #666;
&:last-child {
span {
margin-right: 10px;
&::before {
content: '•';
color: @xtxColor;
margin-right: 2px;
}
}
a {
color: @xtxColor;
}
}
}
}
}
</style>
来吧试试看