基于Vue省市区三级联动组件-PC端
效果演示
CityPicker.gif
使用
<CityPicker v-model="city"></CityPicker>
data() {
return
city: ['', '', '']
}
}
代码
<template>
<div class="city-picker">
<dl v-for="(c, i) in ct" :key="c.name" :class="{ active: show === i }">
<dt @click="show = show === i ? -1 : i">
<span>{{ c.value }}</span>
<i class="iconfont icon-left"></i>
</dt>
<dd>
<div
v-for="(name, key) in c.pic"
:key="key"
class="option"
:class="{ active: key === c.code }"
@click="onChange(c.name, i, key, name)"
>
{{ name }}
</div>
</dd>
</dl>
</div>
</template>
<script>
import { area } from '@/utils/area'
export default {
name: 'CityPicker',
model: {
prop: 'codes',
event: 'change'
},
props: {
codes: { type: Array, default: () => ['', '', ''] }
},
data: () => ({
show: -1,
ct: [
{
name: 'province_list',
pic: area.province_list,
code: '',
value: '请选择'
},
{ name: 'city_list', pic: {}, value: '请选择', code: '' },
{ name: 'county_list', pic: {}, value: '请选择', code: '' }
],
ch: ['', '', '']
}),
watch: {
/**
* @param {string[]} v
*/
codes(v) {
if (JSON.stringify(v) !== JSON.stringify(this.ch)) {
this.ch = v
v.forEach((c, i) => {
const curr = this.ct[i]
curr.code = c
curr.value = curr.pic[c] || '请选择'
if (i + 1 < v.length) {
const next = this.ct[i + 1]
next.pic = this.filter(next.name, c)
}
})
}
}
},
methods: {
filter(name, code) {
const result = {}
const reg = new RegExp('^' + code.replace(/0+$/, '\\d+'))
for (const key in area[name]) {
if (area[name].hasOwnProperty(key) && reg.test(key)) {
result[key] = area[name][key]
}
}
return result
},
onChange(name, ind, code, value) {
const curr = this.ct[ind]
curr.code = code
curr.value = value
if (ind < this.ct.length - 1) {
const next = this.ct[ind + 1]
next.pic = this.filter(next.name, code)
this.onChange(
next.name,
ind + 1,
Object.keys(next.pic)[0],
Object.values(next.pic)[0]
)
} else {
this.show = -1
this.$emit('change', (this.ch = this.ct.map((ct) => ct.code)))
}
}
}
}
</script>
<style lang="less">
.city-picker {
::-webkit-scrollbar {
width: 7px;
}
::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 7px;
}
::-webkit-scrollbar-track {
background-color: #f3f3f3;
}
dl {
float: left;
width: 120px;
height: 40px;
box-sizing: border-box;
vertical-align: middle;
font-size: 0;
cursor: default;
background: #fff;
font-size: 12px;
margin-right: 10px;
position: relative;
&.active {
.iconfont {
transform: rotate(-90deg);
// transform-origin: center center;
}
dd {
display: block;
}
}
dt {
width: 100%;
height: 40px;
line-height: 40px;
border: 1px solid #d3d3d3;
box-sizing: border-box;
position: relative;
span {
display: block;
cursor: pointer;
padding: 0 10px;
width: calc(100% - 28px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
}
i {
cursor: pointer;
display: inline-block;
width: 12px;
height: 12px;
font-size: 12px;
font-weight: bold;
position: absolute;
top: 14px;
right: 10px;
transition: all 0.3s linear;
line-height: 12px;
color: #bbb;
user-select: none;
}
}
dd {
display: none;
width: 118px;
max-height: 168px;
border: 1px solid #d3d3d3;
border-top-width: 0;
position: absolute;
top: 39px;
left: 0;
z-index: 99;
overflow-y: scroll;
background: #fff;
.option {
display: block;
padding: 0 10px;
height: 28px;
line-height: 28px;
cursor: pointer;
width: calc(100% - 20px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
background: #eee;
}
}
}
}
}
</style>
省市区部分编码
export const area = {
province_list: {
110000: '北京',
120000: '天津',
130000: '河北省',
140000: '山西省',
150000: '内蒙古',
210000: '辽宁省',
220000: '吉林省',
230000: '黑龙江省',
310000: '上海',
320000: '江苏省',
330000: '浙江省',
340000: '安徽省',
350000: '福建省',
360000: '江西省',
370000: '山东省',
410000: '河南省',
420000: '湖北省',
430000: '湖南省',
440000: '广东省',
450000: '广西',
460000: '海南省',
500000: '重庆',
510000: '四川省',
520000: '贵州省',
530000: '云南省',
540000: '西藏',
610000: '陕西省',
620000: '甘肃省',
630000: '青海省',
640000: '宁夏',
650000: '新疆',
710000: '台湾',
810000: '香港',
820000: '澳门'
},
city_list: {
110100: '北京市',
110200: '县',
120100: '天津市',
120200: '县',
130100: '石家庄市',
130200: '唐山市',
130300: '秦皇岛市',
130400: '邯郸市',
130500: '邢台市',
130600: '保定市',
130700: '张家口市',