移动端城市区域选择
组件使用
<template>
<div>
<div @click="show=true">
<div>
<span>{{areaName}}</span>
<van-icon name="arrow-down" />
</div>
</div>
<region-pop
v-model="show"
level="village"
:parentLevelCodes="parentLevelCodes"
:parentLevelNames="parentLevelNames"
:disable-level="disableLevel"
@confirm="changeArea"
>
</region-pop>
</div>
</template>
<script>
import { Dialog } from 'vant';
import RegionPop from './RegionPop.vue';
export default {
components:{
RegionPop:RegionPop
},
data(){
return {
show:false,
areaName:'',
areaCode:'',
parentLevelCodes:[], // 将各级数据code值push到数组里
parentLevelNames:[] // 将各级数据name值push到数组里
}
},
mounted(){
// 进入页面获取用户areaCode去查询地区数据
if(this.areaCode){
this.disableLevel=Number(this.$appStroe.getters['location/disableLevel']) || 0;
this.$axios({areaCode:this.areaCode}).then((res)=>{
let data = res;
this.areaName=data.areaName
this.isopen=data;
this.parentLevelCodes.push(data.parentLevelCode);
this.parentLevelNames.push(data.parentLevelName);
this.parentLevelNames.push(data.cityName);
this.parentLevelCodes.push(data.cityCode);
this.parentLevelCodes.push(data.countyCode);
this.parentLevelNames.push(data.countyName);
if(data.townCode){
this.parentLevelNames.push(data.townName)
this.parentLevelCodes.push(data.townCode)
}
if(data.villageCode){
this.parentLevelNames.push(data.villageName)
this.parentLevelCodes.push(data.villageCode)
}
this.$store.commit('location/setAreaName',data.villageName)
this.$store.commit('location/setAreaCode',data.villageCode)
})
}else{
Dialog.alert({
title:'提示',
message:'为定位到当前村请选择!'
}).then(()=>{
this.show=true
}).catch(()=>{
})
}
},
methods:{
changeArea(areaInfo){
this.areaName=areaInfo.areaName;
// 选择到有效村
if(areaInfo.level === 5){
if(areaInfo.status === 'N'){
Dialog.confirm({
title:'提示',
message:'您选择的村庄暂时未入驻',
cancelButtonText:'取消',
confirmButtonText:'确定'
}).then(()=>{
}).catch(()=>{})
}
}else{
Dialog.alert({
title:'提示',
message:'地区需选择到村级'
}).then(()=>{
this.show = true
}).catch(()=>{})
}
}
}
}
</script>
城市区域regionPop组件
<template>
<van-popup>
<div class="bg" @click.self="hideRegion">
<div class="content">
<div class="header">
<span>请选择</span>
<van-icon class="close-btn" size="28" name="success" @click="hideRegion" />
</div>
<v-region
:level="level"
:parentLevelCodes="parentLevelCodes"
:parentLevelNames="parentLevelNames"
:disable-level="disableLevel"
:show-not-active="showNotActive"
@change="changeArea"
>
</v-region>
</div>
</div>
</van-popup>
</template>
<script>
import {Popup,Icon} from 'vant';
import Region from './Region.vue'
export default {
name:'RegionPop',
components:{
[Popup.name]:Popup,
[Icon.name]:Icon,
'v-region':Region
},
model:{
prop:'isShow',
event:'close'
},
props:{
showNotActive:{
type:Boolean,
default:false
},
isShow:{
type:Boolean,
default:false
},
disableLevel:{
type:Number
},
// 向Region中传递
level:{
type:String,
default:'county'
},
parentLevelCodes:{
type:Array,
// default:'130000000000'
},
parentLevelNames:{
type:Array,
// default:()=> []
}
},
data(){
return {
areaInfo:{
areaCode:'000000000000',
areaName:'中国',
areaFullName:'中国',
level:0,
isFullLevel:false,
provinceCode:'',
provinceName:'请选择',
cityCode:'',
cityName:'请选择',
countyCode:'',
countyName:'请选择',
townCode:'',
townName:'请选择',
villageCode:'',
villageName:'请选择',
}
}
},
methods:{
hideRegion(){
this.$emit('confirm',this.areaInfo);
this.$emit('close',false)
},
// 直接向外层传递
changeArea(val){
this.areaInfo=val;
this.$emit('change',val)
}
}
}
</script>
<style scoped>
.pop-wrapper{
height: 100%;
background: none !important;
}
.bg{
width: 100%;
height: 100%;
background: rgba(0,0,0,0.3);
position: relative;
}
.content{
position: absolute;
left:0;
bottom:0;
width:100%;
height: auto
}
.header{
height: 1rem;
line-height: 1rem;
background: #fff;
position: relative;
text-align: center
}
.close-btn{
position: absolute;
top:0.1rem;
right: 0.2rem;
color:#298df8
}
</style>
城市区域region组件
<template>
<!-- 配合底部弹出组件使用<van-popup v-model="show" position="top" :style="{height:'30%'}"></van-popup> -->
<!-- 支持自定义父级和总等级,见props-->
<div class="area-block">
<div>
<van-steps direction="vertical" :active="currentLevel">
<van-step :class="currentLevel >= 0 ? 'selected' : ''">
<span>中国</span>
</van-step>
<van-step :class="currentLevel >= 1 ? 'selected' : ''">
<span class="level-title">省</span>
<span class="level-detail" @click="showNextLevel(1)">{{selectedInfo.provinceName}}</span>
</van-step>
<van-step
v-if="stepLevel >= 2 && selectedInfo.hasCity"
:class="currentLevel >= 2 ? 'selected' : ''"
>
<span class="level-title">市</span>
<span class="level-detail" @click="showNextLevel(2)">{{selectedInfo.cityName}}</span>
</van-step>
<van-step
v-if="stepLevel >= 3 && selectedInfo.hasCounty"
:class="currentLevel >= 3 ? 'selected' : ''"
>
<span class="level-title">区县</span>
<span class="level-detail" @click="showNextLevel(3)">{{selectedInfo.countyName}}</span>
</van-step>
<van-step
v-if="stepLevel >= 4 && selectedInfo.hasTown"
:class="currentLevel >= 4 ? 'selected' : ''"
>
<span class="level-title">乡镇街道</span>
<span class="level-detail" @click="showNextLevel(4)">{{selectedInfo.townName}}</span>
</van-step>
<van-step
v-if="stepLevel >= 5 && selectedInfo.hasVillage"
:class="currentLevel === 5 ? 'selected' : ''"
>
<span class="level-title">村</span>
<span class="level-detail" @click="showNextLevel(5)">{{selectedInfo.villageName}}</span>
</van-step>
</div>
<div class="area-list">
<div class="area-list-title">请选择{{currentLevelName}}</div>
<span
v-for="item in areaList"
v-show="item.areaName"
:key="item.areaCode"
:class="[
'area-item',
selectedInfo.areaCode === item.areaCode ? 'selected2' : '',
item.status === 'Y' || showNotActive ? '' : 'disable'
]"
@click="selectArea(item)"
>
{{ item.areaName }}{{ item.status === 'Y' || showNotActive ? '' : '(未入驻)'}}
</span>
</div>
</div>
</template>
<script>
import {Steps,Step,Popup,Notify} from 'vant';
const NAME_MAPPING={
1:'省',
2:'市',
3:'区县',
4:'乡镇街道',
5:'村'
}
export default {
name:'Region',
components:{
[Popup.name]:Popup,
[Step.name]:Step,
[Steps.name]:Steps
},
props:{
showNotActive:{
type:Boolean,
default:false
},
level:{
type:String,
default:'county'
},
disableLevel:{
type:Number
},
parentLevelCodes:{
type:Array,
default:()=>[]
},
parentLevelNames:{
type:Array,
default:()=>[]
},
},
data(){
return {
selectedInfo:{
areaCode:'000000000000',
areaName:'中国',
areaFullName:'中国',
level:0,
isFullLevel:false,
provinceCode:'',
provinceName:'请选择',
cityCode:'',
cityName:'请选择',
hasCity:true,
countyCode:'',
countyName:'请选择',
hasCounty:true,
townCode:'',
townName:'请选择',
hasTown:true,
villageCode:'',
villageName:'请选择',
hasVillage:true
},
currentLevel:1,
areaList:[]
}
},
computed:{
stepLevel(){
switch(this.level){
case 'province':
return 1;
case 'city':
return 2;
case 'county':
return 3;
case 'town':
return 4;
case 'village':
return 5;
default:
return 5;
}
},
currentLevelName(){
return NAME_MAPPING[this.currentLevel.toString()]
},
areaFullName(){
let fullName='';
if(this.currentLevel>=1){
fullName=this.selectedInfo.provinceName
}
if(this.currentLevel>=2){
fullName=this.selectedInfo.cityName
}
if(this.currentLevel>=3){
fullName=this.selectedInfo.countyName
}
if(this.currentLevel>=4){
fullName=this.selectedInfo.townName
}
if(this.currentLevel>=5){
fullName=this.selectedInfo.villageName
}
return fullName
},
isFullLevel(){
return this.currentLevel === this.stepLevel
}
},
mounted(){
this.initRegions();
this.initRegions2();
if(this.level && this.parentLevelCodes.length>0){
if(this.stepLevel>3){
this.getAreasParenCode(this.parentLevelCodes[this.parentLevelCodes.length-1]).then(
(areaList)=>{
this.areaList=areaList;
if(this.currentLevel !==5){
this.currentLevel++
}
}
)
}
}else{
this.getAreasForNew()
}
},
methods:{
getMaxLeft(val){
if(val && val.length>0){
return '3';
}else if(val && val.length>6){
return '2';
}else{
return '';
}
},
showNextLevel(level){
if(this.disableLevel >= level){
Notify({
type:'warning',
message:'当前地区不允许选择上级'
});
return
}
if(this.currentLevel < level){
Notify({
type:'warning',
message:'请先选择上级地区'
});
return
}
// 重新选择当前层级地区,清空本级和下级数据
this.currentLevel=level;
this.reset()
},
selectArea(areaInfo){
if(areaInfo.level === '1' && areaInfo.areaName !== '辽宁省' && areaInfo.areaCode !== '210000000000'){
Notify({
type:'warning',
message:'只能选择辽宁省'
});
return
}
if(areaInfo.level === '5' && areaInfo.status !== 'Y' && !this.showNotActive){
return 0
}
this.selectedInfo.areaCode=areaInfo.areaCode;
this.selectedInfo.areaName=areaInfo.areaName;
if(this.currentLevel<this.stepLevel){
this.areaList = []
}
switch(this.currentLevel){
case 1:
this.selectedInfo.provinceCode = areaInfo.areaCode;
this.selectedInfo.provinceName = areaInfo.areaName;
break;
case 2:
this.selectedInfo.cityCode = areaInfo.areaCode;
this.selectedInfo.cityName = areaInfo.areaName;
if(/0{8}$/.test(areaInfo.areaCode) === false){
this.selectedInfo.countyCode = areaInfo.areaCode;
this.selectedInfo.countyName = areaInfo.areaName;
this.currentLevel += 1
}
break;
case 3:
this.selectedInfo.countyCode = areaInfo.areaCode;
this.selectedInfo.countyName = areaInfo.areaName;
break;
case 4:
this.selectedInfo.townCode = areaInfo.areaCode;
this.selectedInfo.townName = areaInfo.areaName;
break;
case 5:
this.selectedInfo.villageCode = areaInfo.areaCode;
this.selectedInfo.villageName = areaInfo.areaName;
break;
}
this.selectedInfo.areaFullName = this.areaFullName;
this.selectedInfo.level = this.currentLevel;
this.selectedInfo.isFullLevel = this.isFullLevel;
this.selectedInfo.status = areaInfo.status;
this.$emit('change',this.selectedInfo);
if(this.currentLevel < this.stepLevel){
this.getAreasForNew(true)
}
},
getAreasForNew(val){
this.getAreas().then((areaList)=>{
this.areaList = areaList;
let tempLevel = parseInt(this.areaList[0].level)
if(val){
if(this.currentLevel !== 0 && tempLevel> this.currentLevel + 1){
for(let i =this.currentLevel+1;i<tempLevel;i++){
if(this.currentLevel+1<tempLevel){
this.changeHasLevel(i)
}
}
this.currentLevel =tempLevel
}else{
this.currentLevel +=1
}
}
})
},
changeHasLevel(val){
switch(val){
case 2:
this.selectedInfo.hasCity=false;
break;
case 3:
this.selectedInfo.hasCounty=false;
break;
case 4:
this.selectedInfo.hasTown=false;
break;
case 5:
this.selectedInfo.hasVillage=false;
break;
}
},
getAreasParenCode(val){
return ruleApi.getSonAreaCode(
this.$api,{
areaCode:val,
status:'A'
}).then((res)=>{
return res.childRegionList.map((item)=>{
return {
areaCode:item.areaCode,
areaName:item.areaName,
level:item.level,
status:item.status
}
})
})
},
getAreas(){
return ruleApi.getSonAreaCode(this.$api,{
areaCode:this.selectedInfo.areaCode,
status:'A'
})
.then((res)=>{
return res.childRegionList.map((item)=>{
return {
areaCode:item.areaCode,
areaName:item.areaName,
level:item.level,
status:item.status
}
})
})
},
filterArea(areaCode,_areaList){
let matchedArea = _areaList.find((item)=>item.areaCode === areaCode);
if(matchedArea){
return matchedArea.children || []
}else{
let filteredChildren = [];
let matched = _areaList.some((item)=>{
let {areaCode:code,children} =item;
let len = /0+$/.exec(code)[0].length;
if(len<10 && len>8){
len=8
}
if(len<8 && len>6){
len=6
}
if(len<6 && len>3){
len=3
}
if(len<3){
len=0
}
let prefix = code.slice(0,code.length-len);
if(new RegExp('^'+prefix).test(areaCode)){
filteredChildren = children
return true
}
return false
});
if(matched){
return this.filterArea(areaCode,filteredChildren)
}else{
return []
}
}
},
reset(){
if(this.currentLevel <= 5){
this.selectedInfo.areaCode = this.selectedInfo.townCode;
this.selectedInfo.areaName = this.selectedInfo.townName;
this.selectedInfo.villageCode='';
this.selectedInfo.villageName='请选择'
}
if(this.currentLevel <= 4){
this.selectedInfo.townCode='';
this.selectedInfo.townName='请选择';
if(!this.selectedInfo.hasCounty){
this.selectedInfo.areaCode = this.selectedInfo.cityCode;
this.selectedInfo.areaName = this.selectedInfo.cityName;
}else{
this.selectedInfo.areaCode = this.selectedInfo.countyCode;
this.selectedInfo.areaName = this.selectedInfo.countyName;
}
}
if(this.currentLevel <= 3){
this.selectedInfo.countyCode='';
this.selectedInfo.countyName='请选择';
this.selectedInfo.hasTown=true;
this.selectedInfo.hasVillage=true
if(!this.selectedInfo.hasCity){
this.selectedInfo.areaCode = this.selectedInfo.provinceCode;
this.selectedInfo.areaName = this.selectedInfo.provinceName;
}else{
this.selectedInfo.areaCode = this.selectedInfo.cityCode;
this.selectedInfo.areaName = this.selectedInfo.cityName;
}
}
if(this.currentLevel <= 2){
this.selectedInfo.areaCode = this.selectedInfo.provinceCode;
this.selectedInfo.areaName = this.selectedInfo.provinceName;
this.selectedInfo.cityCode='';
this.selectedInfo.cityName='请选择';
this.selectedInfo.hasCounty=true;
this.selectedInfo.hasTown=true;
this.selectedInfo.hasVillage=true
}
if(this.currentLevel <= 1){
this.selectedInfo.areaCode = '000000000000';
this.selectedInfo.areaName = '';
this.selectedInfo.provinceCode='';
this.selectedInfo.provinceName='请选择';
this.selectedInfo.hasCity=true;
this.selectedInfo.hasCounty=true;
this.selectedInfo.hasTown=true;
this.selectedInfo.hasVillage=true
}
// 重置后始终为当前所在的前一层级
this.selectedInfo.areaFullName=this.areaFullName.slice(0,this.areaFullName.length-3);
this.selectedInfo.level=this.currentLevel-1;
this.selectedInfo.isFullLevel=false;
this.$emit('change',this.selectedInfo);
this.getAreasForNew()
},
initRegions2(){
let levels = this.parentLevelNames.length;
if(levels === 0){
return
}else{
this.selectedInfo.areaCode=this.parentLevelCodes[this.parentLevelCodes.length - 1];
this.selectedInfo.areaName=this.parentLevelNames[this.parentLevelNames.length - 1];
this.selectedInfo.areaFullName=this.parentLevelNames.join('');
this.selectedInfo.level = levels;
this.currentLevel = levels;
if(levels >= 1){
this.selectedInfo.provinceCode=this.parentLevelCodes[0];
this.selectedInfo.provinceName=this.parentLevelNames[0];
}
if(levels >= 2){
this.selectedInfo.cityCode=this.parentLevelCodes[1];
this.selectedInfo.cityName=this.parentLevelNames[1];
}
if(levels >= 3){
this.selectedInfo.countyCode=this.parentLevelCodes[2];
this.selectedInfo.countyName=this.parentLevelNames[2];
}
if(levels >= 4){
this.selectedInfo.townCode=this.parentLevelCodes[3];
this.selectedInfo.townName=this.parentLevelNames[3];
}
if(levels >= 5){
this.selectedInfo.villageCode=this.parentLevelCodes[4];
this.selectedInfo.villageName=this.parentLevelNames[4];
}
if(this.selectedInfo.cityName === this.selectedInfo.countyName){
this.selectedInfo.hasCounty = false
}
this.$emit('change',this.selectedInfo)
}
},
resetData(){
this.selectedInfo.provinceCode = '';
this.selectedInfo.provinceName = '请选择';
this.selectedInfo.cityCode = '';
this.selectedInfo.cityName = '请选择';
this.selectedInfo.countyCode = '';
this.selectedInfo.countyName = '请选择';
this.selectedInfo.townCode = '';
this.selectedInfo.townName = '请选择';
this.selectedInfo.villageCode = '';
this.selectedInfo.villageName = '请选择';
this.selectedInfo.areaCode = '000000000000';
this.selectedInfo.areaName = '中国';
this.currentLevel=1;
this.selectedInfo.areaFullName='中国';
this.getAreasForNew();
this.$emit('change',this.selectedInfo)
},
initRegions(){
if(this.disableLevel === 0){
return
}else{
this.selectedInfo.areaCode=this.parentLevelCodes[this.parentLevelCodes.length - 1];
this.selectedInfo.areaName=this.parentLevelNames[this.parentLevelNames.length - 1];
this.selectedInfo.areaFullName=this.parentLevelNames.join('');
this.selectedInfo.level = this.disableLevel;
this.currentLevel = this.disableLevel + 1;
if(this.disableLevel >= 1){
this.selectedInfo.provinceCode=this.parentLevelCodes[0];
this.selectedInfo.provinceName=this.parentLevelNames[0];
}
if(this.disableLevel >= 2){
this.selectedInfo.cityCode=this.parentLevelCodes[1];
this.selectedInfo.cityName=this.parentLevelNames[1];
}
if(this.disableLevel >= 3){
this.selectedInfo.countyCode=this.parentLevelCodes[2];
this.selectedInfo.countyName=this.parentLevelNames[2];
}
if(this.disableLevel >= 4){
this.selectedInfo.townCode=this.parentLevelCodes[3];
this.selectedInfo.townName=this.parentLevelNames[3];
}
if(this.disableLevel >= 5){
this.selectedInfo.villageCode=this.parentLevelCodes[4];
this.selectedInfo.villageName=this.parentLevelNames[4];
}
this.$emit('change',this.selectedInfo)
}
}
}
}
</script>
<style scoped>
.level-title{
display: inline-block;
width:2rem
}
.level-detail{
min-width: 2rem;
}
.area-block{
width:100%;
height: 100%;
position: relative;
background: #fff;
}
.area-item{
padding:0.1rem 0.3rem;
font-size:15px;
display: block;
margin: 5px;
color:#298df8
}
.area-list{
padding:0.5rem 0;
overflow-y:scroll ;
height: 5rem;
}
.area-list-title{
margin-left:0.2rem;
color:black
}
.disable{
color:gray
}
.selected{
color:#298df8
}
.selected2{
position: relative;
}
.selected2::after{
content: '\F0C8';
display: inline-block;
color: #57bda2;
position: absolute;
top:4px;
width: 1em;
height: 1em;
font-size:16px;
font-family: "vant-icon";
}
.animate{
width: 100%;
display: inline-block;
white-space: nowrap;
animation: 2s wordsLoop linear infinite normal;
}
.marquee-block{
display: inline-block;
width: 100%;
height: 100%;
box-sizing:border-box;
position: relative
}
.marquee{
animation: marquee 2s liner infinite;
white-space: nowrap;
position: absolute;
}
.marqueeT{
animation: marqueeT 2s liner infinite;
white-space: nowrap;
position: absolute;
}
.marquee2{
animation: marquee2 2s liner infinite;
white-space: nowrap;
position: absolute;
}
.marqueeT2{
animation: marqueeT2 2s liner infinite;
white-space: nowrap;
position: absolute;
}
.marquee3{
animation: marquee3 2s liner infinite;
white-space: nowrap;
position: absolute;
}
.marqueeT3{
animation: marqueeT3 2s liner infinite;
white-space: nowrap;
position: absolute;
}
@keyframes marquee{
0%{
left:0;
}
100%{
left:-170%
}
}
@keyframes marqueeT{
0%{
left:170%;
}
100%{
left:0
}
}
@keyframes marquee2{
0%{
left:0
}
100%{
left:-280%
}
}
@keyframes marqueeT2{
0%{
left:280%
}
100%{
left:0
}
}
@keyframes marquee3{
0%{
left:0
}
100%{
left:-360%
}
}
@keyframes marqueeT3{
0%{
left:360%
}
100%{
left:0
}
}
</style>