Vue项目使用mt-picker实现省市区三级联动踩坑记录

2023-08-25 12:43:09 浏览数 (3)

最近用 Vue 开发一个项目,需要实现一个省市区三级联动的功能。

使用的是饿了么团队的移动端组件库 Mint UI 中的 Picker 组件,官方的文档也是十分的不详细。

我期间遇到了不少问题,踩了一些坑,下次记录一下,希望能对大家和以后的自己有所帮助。

Mint UI 的使用,我就不再赘述的,大家需要的话可以根据官方文档进行下载和使用。下面开始进入正题:

我这里使用的是后端提供的省市区数据接口,为了方便最下面代码的理解,我再次贴一下我所使用的数据:省市区三级联动数据

您也可以直接下载我提供的 json 文件:点击下载

picker 的使用(HTML):我这里搭配了 popup 使用。

代码语言:javascript复制
<mt-popup v-model="popupVisible" position="bottom">
  <div class="pickerTitle">
    <a-button type="link" @click="popupClose">取消</a-button>
    <h4>选择地区</h4>
    <a-button type="link" @click="handlePopup">确定</a-button>
  </div>
  <mt-picker v-if="addSlots.length === 0"></mt-picker>
  <mt-picker v-else
             :slots="addSlots"
             value-key="name"
             :itemHeight="50"
             :visibleItemCount="3"
             @change="addressChange">
  </mt-picker>
</mt-popup>

JS 部分代码:

因为保存数据时,后台不进去要省市区的名字,而且需要省市区的 id ,所以 values 我是这样写的。

因为北京只有市和区,没有省的数据,所以初始化的时候没有设置第三个 slot 的值。

代码语言:javascript复制
data () {
  return {
    popupVisible: false,
    addData: [],
    addSlots: [{
      flex: 1, //对应 slot CSS 的 flex 值
      values: [ //省份数组
        {
          code: '',
          name: '',
          key: 0,
        }
      ],
      className: 'slot1', //对应 slot 的类名
      textAlign: 'right' //对应 slot 的对齐方式
    }, {
      flex: 1,
      values: [
        {
          code: '',
          name: '',
          key: 0,
        }
      ],
      className: 'slot2'
    }, {
      flex: 1,
      values: undefined,
      className: 'slot3',
      textAlign: 'left'
    }],
    addValue: [//确定时赋值
      {name:'',code:''},//省
      {name:'',code:''},//市
      {name:'',code:''},//区
    ],
    addValue1: [//选中的数据
      {name:'',code:''},//省
      {name:'',code:''},//市
      {name:'',code:''},//区
    ],
  }
},
methods: {
  getRegion(){//获取省市区数据,需要一个初始值。
    let that = this,
          add = [], add1 = [],
          pd = that.addData,
          cd = pd[0].child;
        for (let prop in pd) {
          add.push({name: pd[prop].title, code: pd[prop].ad_code, key: Number(prop)})
        }
        that.addSlots[0].values = add //设置组件的省数据
        for (let prop in cd) {
          add1.push({name: cd[prop].title, code: cd[prop].ad_code, key: Number(prop)})
        }
        that.addSlots[1].values = add1 //设置组件的市的数据
  },
  popupShow (type) {
    let that = this;
    that.popupVisible = true;
  },
  popupClose () {
    this.popupVisible = false;
  },
  addressChange (picker, values) {//选中数据改变时
    let that = this;
    if (that.addData[values[0].key]) { //判断省的key值,类似于 v-if 的效果(可以不加,但是会报错,很不爽)
      let cd = that.addData[values[0].key].child, //市的数据
        ad = cd[values[1].key].child, //区的数据
        c = [],
        a = [];
      for (let i in cd) {
        c.push({name: cd[i].title, code: cd[i].ad_code, key: Number(i)}) //循环出市的数据
      }
      picker.setSlotValues(1, c);//赋给第二个 slot
      for (let i in ad) {
        a.push({name: ad[i].title, code: ad[i].ad_code, key: Number(i)}) //循环出区的数据
      }
      picker.setSlotValues(2, a); //复制给第三个 slot
      for (let i in values){ // 将选中的数据缓存一下
        if (values[i]) {
          that.addValue1[i].code = values[i].code;
          that.addValue1[i].name = values[i].name;
        } else {
          that.addValue1[i].code = '';
          that.addValue1[i].name = '';
        }
      }
    }
  },
  handlePopup () { //点击确实时,将缓存的数据赋值给 addValue ,实现前端显示。
    for (let i in this.addValue){
      if (this.addValue[i]) {
        this.addValue[i].code = this.addValue1[i].code;
        this.addValue[i].name = this.addValue1[i].name;
      }
    }
    this.popupVisible = false;
  }
},

遇到的问题:

开始我我封装了一个方法,在 picker 变化时,直接修改 this.addSlots ,发现在滑动第二个 slot 的时候不能检测数据变化,无法缓存数据。

需要使用 picker 的 picker.setSlotValues(2, a) 属性给 slot 赋值。

picker.setSlotValues(index, value):

这里的 index 是 slot 的下标,2 就代表第三个 slot。

value 代表 slot 的 values 的值。

这样就可以实现省市区三级联动了。

1 人点赞