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 .pic2{ 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 h4{ 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 '~@/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 .pic2{ 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 h4{ 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>





哈哈,效果就实现了










友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信