您现在的位置:首页 >> 前端 >> 内容

vue实现仿京东、淘宝省市区三级联动的代码教程

时间:2018/4/19 14:28:39 点击:

  核心提示:vue 实现仿京东、淘宝省市区三级联动在做电商或其他项目的时候,物流我们肯定会集成进去,那么我们肯定需要集成地址管理,地址管理除了最基本的省、市、区外,我们还要单独添加一个详细地址字段,不然我们无法精...

vue 实现仿京东、淘宝省市区三级联动

在做电商或其他项目的时候,物流我们肯定会集成进去,那么我们肯定需要集成地址管理,地址管理除了最基本的省、市、区外,我们还要单独添加一个详细地址字段,不然我们无法精确到详细地址,那么最后我们的详细地址就是省市区加上我们的详细地址字段,好了,我们先来看一下省市区三级联动的效果图

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>

哈哈,效果就实现了

Tags:VU UE E实 实现 
作者:网络 来源:诗雨远方的博客