vue用mint-ui的picker组件封装一个省市区三级联动组件

    最近公司在用vue做项目,然后需要做一个省市区的三级联动的功能,于是研究了一下mint-ui,写了效果如下的一个组件

首先我们的数据文件如下形式,将他分开成一个js文件并将数据暴露出来:

cityData.js

export const CITY_DATA= [
  {
    "id": "110000",
    "name": "北京市",
    "city": [
      {
        "id": "110100",
        "name": "北京市",
        "district": [
          {
            "id": "110101",
            "name": "东城区"
          },{
            "id": "110102",
            "name": "西城区"
          }]
       }]
}]

然后子组件需要实现三级联动的效果,并将用户的选择结果(选择的城市及对应的id)返回到父组件,内容如下:

linkage.vue

<template>
  <div>
    <div class="mask" @click="_hideLinkage"></div>
    <div class="clearfix linkage">
      <div class="province pickerWrapper">
        <mt-picker :slots="provinces" @change="onProvinceChange" value-key="name"></mt-picker>
      </div>
      <div class="city pickerWrapper">
        <mt-picker :slots="citys" @change="onCityChange" value-key="name"></mt-picker>
      </div>
      <div class="area pickerWrapper">
        <mt-picker :slots="areas" @change="onAreaChange" value-key="name"></mt-picker>
      </div>
    </div>
  </div>
</template>

<script>
import {CITY_DATA} from '../../api/cityData'  //引入cityData数据
export default {
  computed: {
    result() {
      return {
        name:this.province.name+this.city.name+this.area.name,
        id:this.province.id+','+this.city.id+','+this.area.id
    }
    }
  },
  data() {
    return {
      province:{
        name:'四川省',
        id:'510000'
      },
      maskFlag:false,
      city:{
        name:'成都市',
        id:'510100'
      },
      area:{
        name:'市辖区',
        id:'510101'
      },
      flag:0, //最开始省市区那三个picker会初始化调用change事件,但是此时没有省市区数据,因此会报错,
              //所以以这个标识符来控制当时第一次初始化时调用change事件时直接return
      provinces: [
        {
          flex: 1,
          values: this._getProvince(),
          className: 'slot1',
          textAlign: 'center'
        }, {
          divider: true,
          content: '-',
          className: 'right'
        }
      ],
      citys: [
        {
          flex: 1,
          values: this._getCity('四川省'),
          className: 'slot1',
          textAlign: 'center'
        }, {
          divider: true,
          content: '-',
          className: 'slot2'
        }
      ],
      areas: [
        {
          flex: 1,
          values: this._getArea('四川省','成都市'),
          className: 'slot1',
          textAlign: 'center'
        }
      ]

    };
  },
  methods:{
    _hideLinkage(){
      this.$emit('getLinkage',this.result); //触发父组件的getLinkage事件接收结果数据
    },
    onProvinceChange(picker, values) {
      if(this.flag===0){
        return
      }
      let provinceIndex=picker.getSlotValue(0)
      this.province=provinceIndex
      let city=this._getCity(provinceIndex.name)
      this.citys[0].values=city
      this.city=city[0]
    },
    onCityChange(picker, values) {
      if(this.flag===0){
        return
      }
      let cityIndex=picker.getSlotValue(0)
      this.city=cityIndex
      let provinceIndex=this.province
      let area=this._getArea(provinceIndex.name,cityIndex.name)
      this.areas[0].values=area
      this.area=area[0]
    },
    onAreaChange(picker, values) {
      if(this.flag===0){
        this.flag=1
        return
      }
      let areaIndex=picker.getSlotValue(0)
      this.area=areaIndex
    },
    //得到省份数据
    _getProvince(){
      let province=[]
      CITY_DATA.forEach(function(item,index){
        let obj={}
        obj.id=item.id
        obj.name=item.name
        province.push(obj)
      })
      return province
    },
    //根据省份得到城市数据
    _getCity(province){
      let city=[]
      CITY_DATA.forEach((item,index)=>{
        if(item.name === province){
          item.city.forEach((item,index)=>{
            let obj={}
            obj.id=item.id
            obj.name=item.name
            city.push(obj)
            return
          })
        }
      })
      return city
    },
    //根据城市和省份得到区域数据
    _getArea(province,city){
      let area=[]
      CITY_DATA.forEach((item,index)=>{
        if(item.name === province){
          item.city.forEach((item,index)=>{
            if(item.name === city){
              item.district.forEach((item)=>{
                let obj={}
                obj.id=item.id
                obj.name=item.name
                area.push(obj)
                return
              })
            }
          })
        }
      })
      if(area.length==0){ //如果没有区域数据则第三个picker显示的内容
        area.push({
          name:'没有',
          id:'000000'
        })
      }
      return area
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .mask{
    position: fixed;
    top:0;
    left:0;
    height: 100%;
    width: 100%;
    background: rgba(0,0,0,0.5);
  }
  .linkage{
    position: fixed;
    bottom: 0;
    width: 100%;
    background: white;
    left: 0;
    overflow: hidden;
  }
  .clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}
  .pickerWrapper{
    width:33.3%;
    float: left;
  }


</style>

父组件只需要引入子组件,并得到用户选择的结果,展示在自己的页面上,内容如下:

parent.vue

<template>
  <div>
    <transition name="fade">
      <linkage @getLinkage='_showChildMsg' v-show="showLinkage"></linkage>
    </transition>
    <p v-html="result" class="getCity" @click="_showLinkage"></p>
    <p v-html="id" class="getCity" ></p>
  </div>
</template>

<script type="text/ecmascript-6">
  import Linkage from '../base/linkage/linkage' //引入子组件

export default{
    data(){
      return{
        showLinkage:false, //控制子组件的显示隐藏
        result:'请选择所在省市',
        id:'显示对应id'
      }
    },
  components:{
    Linkage, //注册子组件
  },
  methods:{
    _showChildMsg(msg){ //接收子组件数据
      this.result = msg.name
      this.id=msg.id
      this.showLinkage=false
    },
    _showLinkage(){
      this.showLinkage=true
    }
  }
}
</script>

<style scoped >
.getCity{
  font-size: 20px;
}
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to  {
  opacity: 0;
}

</style>

到这里,我们的三级联动组件就封装好了,这种公用的组件可以放到项目公用的文件里,以后在其他组件中也可以调用

转载于:https://my.oschina.net/u/3689373/blog/1633773

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值