vue 實現仿京東、淘寶省市區三級聯動

vue 實現仿京東、淘寶省市區三級聯動

在做電商或其他項目的時候,物流我們肯定會集成進去,那麼我們肯定需要集成地址管理,地址管理除了最基本的省、市、區外,我們還要單獨添加一個詳細地址字段,不然我們無法精確到詳細地址,那麼最後我們的詳細地址就是省市區加上我們的詳細地址字段,好了,我們先來看一下省市區三級聯動的效果圖

其實這個功能可以封裝成一個組件呢,我這裏面集成了VUX移動端組件,你用的時候html裏面加入,代碼本來是對齊規範的,但是貼上來就變形了

1、html代碼

< cell is-link title = "所屬地區" class = "require" @click.native = " choseAdd () " value-align = "left" >
< p style = "margin-left: 20px" >
{{ receptAddtess . receiptProvince === '' ? "請選擇" : receptAddtess . receiptProvince }} {{ receptAddtess . receiptCity }} {{ receptAddtess . receiptArea }}
</ p >
</ cell >

<!-- 省市區三級聯動 -->
< section class = "myAddress" >
<!-- 居住地址三級聯動選項 -->
< section class = "showChose" v-show = " showChose " >
< section class = "address" >
< section class = "titleTop" >
< div class = "titleTopLeft" >
< span > 選擇地址 </ span >
</ div >
< div class = "titleTopRight" >
< span @click = " closeAdd () " > × </ span >
</ div >
</ section >
< hr style = "height:1px;border:none;border-top:1px solid #EEEEEE;" >
< section class = "title" >
< div class = "area" @click = " provinceSelected () " >
< span > {{ Province ? Province : info [ province - 1 ]. name }} </ span >
</ div >
< div class = "area" @click = " citySelected () " :class = " City ? '' : 'active' " >
{{ City ? City : '請選擇' }}
</ div >
< div class = "area" @click = " districtSelected () " :class = " District ? '' : 'active' " v-show = " City " >
{{ District ? District : '請選擇' }}
</ div >
</ section >
< hr style = "height:1px;border:none;border-top:1px solid #EEEEEE;" >
< ul >
< li class = "addList" v-for = " ( v , k ) in info " :key = " ( v , k ). index "
@click = " getProvinceId ( v . id , v . name , k ) "
v-show = " showProvince "
:class = " v . selected === true ? 'active' : '' " > {{ v . name }} </ li >
< li class = "addList" v-for = " ( v , k ) in showCityList " :key = " ( v , k ). index "
@click = " getCityId ( v . id , v . name , k ) "
v-show = " showCity "
:class = " v . selected ? 'active' : '' " > {{ v . name }} </ li >
< li class = "addList" v-for = " ( v , k ) in showDistrictList " :key = " ( v , k ). index "
@click = " getDistrictId ( v . id , v . name , k ) "
v-show = " showDistrict "
:class = " v . selected ? 'active' : '' " > {{ v . name }} </ li >
</ ul >
</ section >
</ section >
</ section >

2、js方法如下

choseAdd () {
this . showChose = true
},
closeAdd () {
this . showChose = false
},
_filter ( add , name , code ) {
let result = []
for ( let i = 0 ; i < add . length ; i ++ ) {
if ( code === add [ i ]. id ) {
result = add [ i ][ name ]
}
}
return result
},
getProvinceId : function ( code , input , index ) {
this . province = code
this . Province = input
this . showProvince = false
this . showCity = true
this . showDistrict = false
this . showCityList = this . _filter ( this . info , 'city' , this . province )
// 點擊選擇當前
this . info . map ( a => { a . selected = false })
this . info [ index ]. selected = true
this . receptAddtess . receiptProvince = input
},
provinceSelected : function () {
// 清除市級和區級列表
this . showCityList = false
this . showDistrictList = false
// 清除市級和區級選項
this . City = false
this . District = false
// 選項頁面的切換
this . showProvince = true
this . showCity = false
this . showDistrict = false
},
getCityId : function ( code , input , index ) {
this . city = code
this . City = input
this . showProvince = false
this . showCity = false
this . showDistrict = true
this . showDistrictList = this . _filter ( this . showCityList , 'district' , this . city )
// 選擇當前添加active
this . showCityList . map ( a => { a . selected = false })
this . showCityList [ index ]. selected = true
this . receptAddtess . receiptCity = input
},
citySelected : function () {
this . showProvince = false
this . showCity = true
this . showDistrict = false
},
getDistrictId : function ( code , input , index ) {
this . district = code
this . District = input
// 選擇當前添加active
this . showDistrictList . map ( a => { a . selected = false })
this . showDistrictList [ index ]. selected = true
// 選取市區選項之後關閉彈層
this . showChose = false
this . receptAddtess . receiptArea = input
},
districtSelected : function () {
this . showProvince = false
this . showCity = false
this . showDistrict = true
}

3、css代碼如下

// 省市區三級聯動CSS
. myAddress . cont {
border-bottom: 1px solid rgba (245,245,245,0.8);
}
. myAddress . cont span {
display: inline-block ;
font-size: 0.28rem;
color: #333;
line-height: 0.88rem;
margin-left: 0.32rem;
}
. myAddress . cont section {
float:left ;
}
. myAddress . cont p {
display: inline-block ;
font-size: 0.28rem;
color: #333333;
line-height: 0.88rem;
margin-left: 1rem;
}
. myAddress . cont . pic 2{
float: right ;
width: 0.14rem;
height: 0.24rem;
margin: 0.32rem 0.32rem 0.32rem 0;
}
. myAddress . cont p . text {
margin-left: 0.72rem;
}
. showChose {
width: 100%;
height: 100%;
position:fixed ;
top: 0;
left: 0;
z-index: 120;
background:rgba (77,82,113,0.8);
}
. address {
. titleTop {
display inline
text-align center
. titleTopLeft {
padding-top 5px
padding-bottom 5px
span {
font-size 18px
}
}
. titleTopRight {
span {
position absolute
right 10px
top -5px
font-size 30px
color: #929292
}
}
}
position:absolute ;
bottom: 0;
left: 0;
z-index: 121;
background: # fff ;
width: 100%;
height: 430px
}

. title {
padding-top 4px
padding-bottom 5px
}
. title h 4{
display:inline-block ;
font-size: 18px;
font-weight:normal ;
}
. area {
display:inline-block ;
font-size: 15px;
margin-left: 25px;
}
. addList {
width: 85%;
padding-left: 0.32rem;
font-size: 15px;
line-height: 32px;
}
/* 修改的格式 */
. address ul {
width: 95%;
height: 78%;
overflow:auto ;
}
. address ul li {
margin-left: 20px;
}
. address . title . active {
color:red ;
border-bottom: 0.02rem solid red ;
}
. address ul . active {
color:red ;
}

完成的一個界面如下,我這裏面還調了接口,但是利用上面的代碼就可以集成了,我的界面完成代碼如下

< template >
< div class = "modifyAddress" >
< v-header title = "添加地址" ref = "header" >
< div slot = "right" class = "headerRight" style = "top: 2px; right: 5px;" @click = " handleSaveInfo " >
< span > 保存 </ span >
</ div >
</ v-header >
< div class = "inputWrapper" >
< x-input placeholder = "請輸入收貨人姓名" v-model = " receptAddtess . receiptName " >
< p slot = "label" style = "margin-right:20px" >
< font color = "red" > * </ font > 暱稱 </ p >
</ x-input >
< x-input :max = " 13 " is-type = "china-mobile" placeholder = "請輸入手機號碼" v-model = " receptAddtess . receiptPhone " >
< p slot = "label" style = "margin-right:20px" >
< font color = "red" > * </ font > 手機號碼 </ p >
</ x-input >
< cell is-link title = "所屬地區" class = "require" @click.native = " choseAdd () " value-align = "left" >
< p style = "margin-left: 20px" >
{{ receptAddtess . receiptProvince === '' ? "請選擇" : receptAddtess . receiptProvince }} {{ receptAddtess . receiptCity }} {{ receptAddtess . receiptArea }}
</ p >
</ cell >

<!-- 省市區三級聯動 -->
< section class = "myAddress" >
<!-- 居住地址三級聯動選項 -->
< section class = "showChose" v-show = " showChose " >
< section class = "address" >
< section class = "titleTop" >
< div class = "titleTopLeft" >
< span > 選擇地址 </ span >
</ div >
< div class = "titleTopRight" >
< span @click = " closeAdd () " > × </ span >
</ div >
</ section >
< hr style = "height:1px;border:none;border-top:1px solid #EEEEEE;" >
< section class = "title" >
< div class = "area" @click = " provinceSelected () " >
< span > {{ Province ? Province : info [ province - 1 ]. name }} </ span >
</ div >
< div class = "area" @click = " citySelected () " :class = " City ? '' : 'active' " >
{{ City ? City : '請選擇' }}
</ div >
< div class = "area" @click = " districtSelected () " :class = " District ? '' : 'active' " v-show = " City " >
{{ District ? District : '請選擇' }}
</ div >
</ section >
< hr style = "height:1px;border:none;border-top:1px solid #EEEEEE;" >
< ul >
< li class = "addList" v-for = " ( v , k ) in info " :key = " ( v , k ). index "
@click = " getProvinceId ( v . id , v . name , k ) "
v-show = " showProvince "
:class = " v . selected === true ? 'active' : '' " > {{ v . name }} </ li >
< li class = "addList" v-for = " ( v , k ) in showCityList " :key = " ( v , k ). index "
@click = " getCityId ( v . id , v . name , k ) "
v-show = " showCity "
:class = " v . selected ? 'active' : '' " > {{ v . name }} </ li >
< li class = "addList" v-for = " ( v , k ) in showDistrictList " :key = " ( v , k ). index "
@click = " getDistrictId ( v . id , v . name , k ) "
v-show = " showDistrict "
:class = " v . selected ? 'active' : '' " > {{ v . name }} </ li >
</ ul >
</ section >
</ section >
</ section >

< x-textarea placeholder = "街道、樓牌號等" :show-counter = " false " :rows = " 1 " autosize v-model = " receptAddtess . detailAddress " >
< p slot = "label" style = "margin-right:20px" >
< font color = "red" > * </ font > 詳細地址 </ p >
</ x-textarea >
</ div >
<!-- 是否默認地址 -->
< div class = "recommededWrapper" >
< x-switch title = "設爲默認地址" :value-map = " [ 0 , 1 ] " v-model = " receptAddtess . defaultAddress " @on-change = " ifDefault " ></ x-switch >
</ div >
</ div >
</ template >

< script >
import VHeader from '@/components/v-header/v-header'
import { XInput , Group , Cell , XTextarea , XSwitch } from 'vux'
import axios from '@/api/axiosApi'
import info from '@/assets/json/address.json'
import { localUser } from '@/assets/js/local'
export default {
data () {
return {
pageTitle: '居住地址' ,
address: '' ,
showChose: false ,
showProvince: true ,
showCity: false ,
showDistrict: false ,
showCityList: false ,
showDistrictList: false ,
province: 1 ,
city: 3 ,
district: 57 ,
GetProvinceId: 2 ,
District: false ,
Province: false ,
City: false ,
// areaProvince: '',
// areaCity: '',
// areaDistrict: '',
// v-for循環判斷是否爲當前
selected: false ,
info ,
receptAddtess: {
userId: '' ,
receiptName: '' ,
receiptPhone: '' ,
detailAddress: '' ,
defaultAddress: 0 ,
receiptProvince: '' ,
receiptCity: '' ,
receiptArea: ''
}
}
},
mounted () {
},
created () {
},
methods: {
handleSaveInfo () {
if ( this . receptAddtess . receiptName === '' ) {
this . $vux . toast . text ( '收貨人不能爲空' , 'middle' )
return
}
if ( this . receptAddtess . receiptPhone === '' ) {
this . $vux . toast . text ( '電話號碼不能爲空' , 'middle' )
return
}
if ( this . receptAddtess . receiptProvince === '' ) {
this . $vux . toast . text ( '所屬地區不能爲空' , 'middle' )
return
}
if ( this . receptAddtess . detailAddress === '' ) {
this . $vux . toast . text ( '詳細地址不能爲空' , 'middle' )
return
}
this . handleAddReceptAddress ()
},
ifDefault ( value ) {
this . receptAddtess . defaultAddress = value
},
// 添加收貨地址,每個用戶不超過20個地址
handleAddReceptAddress () {
this . receptAddtess . userId = localUser . get ( 'id' )
axios . post ( this , '/v1/receiptAddress' , this . receptAddtess , ( data ) => {
this . $vux . confirm . show ({
title: '溫馨提示' ,
content: '添加地址成功'
})
})
},
choseAdd () {
this . showChose = true
},
closeAdd () {
this . showChose = false
},
_filter ( add , name , code ) {
let result = []
for ( let i = 0 ; i < add . length ; i ++ ) {
if ( code === add [ i ]. id ) {
result = add [ i ][ name ]
}
}
return result
},
getProvinceId : function ( code , input , index ) {
this . province = code
this . Province = input
this . showProvince = false
this . showCity = true
this . showDistrict = false
this . showCityList = this . _filter ( this . info , 'city' , this . province )
// 點擊選擇當前
this . info . map ( a => { a . selected = false })
this . info [ index ]. selected = true
this . receptAddtess . receiptProvince = input
},
provinceSelected : function () {
// 清除市級和區級列表
this . showCityList = false
this . showDistrictList = false
// 清除市級和區級選項
this . City = false
this . District = false
// 選項頁面的切換
this . showProvince = true
this . showCity = false
this . showDistrict = false
},
getCityId : function ( code , input , index ) {
this . city = code
this . City = input
this . showProvince = false
this . showCity = false
this . showDistrict = true
this . showDistrictList = this . _filter ( this . showCityList , 'district' , this . city )
// 選擇當前添加active
this . showCityList . map ( a => { a . selected = false })
this . showCityList [ index ]. selected = true
this . receptAddtess . receiptCity = input
},
citySelected : function () {
this . showProvince = false
this . showCity = true
this . showDistrict = false
},
getDistrictId : function ( code , input , index ) {
this . district = code
this . District = input
// 選擇當前添加active
this . showDistrictList . map ( a => { a . selected = false })
this . showDistrictList [ index ]. selected = true
// 選取市區選項之後關閉彈層
this . showChose = false
this . receptAddtess . receiptArea = input
},
districtSelected : function () {
this . showProvince = false
this . showCity = false
this . showDistrict = true
}
},
components: {
VHeader ,
XInput ,
Group ,
Cell ,
XTextarea ,
axios ,
XSwitch ,
localUser
}
}
</ script >

< style lang = "stylus" scoped >
@ import '[email protected]/assets/css/variable.styl'
. modifyAddress {
position: fixed ;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: $ color-background ;
z-index: 101;
height: 100%;
}

. inputWrapper {
background-color white

}
// 省市區三級聯動CSS
. myAddress . cont {
border-bottom: 1px solid rgba (245,245,245,0.8);
}
. myAddress . cont span {
display: inline-block ;
font-size: 0.28rem;
color: #333;
line-height: 0.88rem;
margin-left: 0.32rem;
}
. myAddress . cont section {
float:left ;
}
. myAddress . cont p {
display: inline-block ;
font-size: 0.28rem;
color: #333333;
line-height: 0.88rem;
margin-left: 1rem;
}
. myAddress . cont . pic 2{
float: right ;
width: 0.14rem;
height: 0.24rem;
margin: 0.32rem 0.32rem 0.32rem 0;
}
. myAddress . cont p . text {
margin-left: 0.72rem;
}
. showChose {
width: 100%;
height: 100%;
position:fixed ;
top: 0;
left: 0;
z-index: 120;
background:rgba (77,82,113,0.8);
}
. address {
. titleTop {
display inline
text-align center
. titleTopLeft {
padding-top 5px
padding-bottom 5px
span {
font-size 18px
}
}
. titleTopRight {
span {
position absolute
right 10px
top -5px
font-size 30px
color: #929292
}
}
}
position:absolute ;
bottom: 0;
left: 0;
z-index: 121;
background: # fff ;
width: 100%;
height: 430px
}

. title {
padding-top 4px
padding-bottom 5px
}
. title h 4{
display:inline-block ;
font-size: 18px;
font-weight:normal ;
}
. area {
display:inline-block ;
font-size: 15px;
margin-left: 25px;
}
. addList {
width: 85%;
padding-left: 0.32rem;
font-size: 15px;
line-height: 32px;
}
/* 修改的格式 */
. address ul {
width: 95%;
height: 78%;
overflow:auto ;
}
. address ul li {
margin-left: 20px;
}
. address . title . active {
color:red ;
border-bottom: 0.02rem solid red ;
}
. address ul . active {
color:red ;
}

. recommededWrapper {
margin-top 10px
background-color white
}
</ style >

< style >
.modifyAddress .require .vux-label:before {
content : '*' ;
display : inline-block ;
color : red ;
}
</ style >



哈哈,效果就實現了