核心提示: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"> <p class="titleTopLeft"> <span>选择地址</span> </p> <p class="titleTopRight"> <span @click="closeAdd()">×</span> </p> </section> <hr style="height:1px;border:none;border-top:1px solid #EEEEEE;" > <section class="title"> <p class="area" @click="provinceSelected()"> <span>{{Province?Province:info[province-1].name}}</span> </p> <p class="area" @click="citySelected()" :class="City?'':'active'"> {{City?City:'请选择'}} </p> <p class="area" @click="districtSelected()" :class="District?'':'active'" v-show="City"> {{District?District:'请选择'}} </p> </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> <p class="modifyAddress"> <v-header title="添加地址" ref="header"> <p slot="right" class="headerRight" style="top: 2px; right: 5px;" @click="handleSaveInfo"> <span>保存</span> </p> </v-header> <p 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"> <p class="titleTopLeft"> <span>选择地址</span> </p> <p class="titleTopRight"> <span @click="closeAdd()">×</span> </p> </section> <hr style="height:1px;border:none;border-top:1px solid #EEEEEE;" > <section class="title"> <p class="area" @click="provinceSelected()"> <span>{{Province?Province:info[province-1].name}}</span> </p> <p class="area" @click="citySelected()" :class="City?'':'active'"> {{City?City:'请选择'}} </p> <p class="area" @click="districtSelected()" :class="District?'':'active'" v-show="City"> {{District?District:'请选择'}} </p> </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> </p> <!-- 是否默认地址 --> <p class="recommededWrapper"> <x-switch title="设为默认地址" :value-map="[0, 1]" v-model="receptAddtess.defaultAddress" @on-change="ifDefault"></x-switch> </p> </p> </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>
哈哈,效果就实现了