demand

Currently in the development of small programs, met a demand, need to choose a province/city/district, today write a simple solution

The solution

1. Try components

Currently, vant, the UI library, is used in the development of mini programs. Vant-appellate p itself provides the component ADDRESS, but the data structure returned by the interface of this project is as follows:

  • To choose the province
  • Then call the interface to get the city under the province
  • Then call the interface to get the region under this city

However, van-address needs to use the data of all provinces and cities. Since adding an interface requires passing in the id of the province and city back, it is not practical to use the component directly.

2. Strike out on a different path

To build the skeleton

But Vant provides another component, the van-picker, which starts with the basic picker.

<van-picker column="{{data}}" />
Copy the code

According to the Vant documentation, column is the data for the entire picker, which is the structure you need if you want multiple selections

/ / a column
data: ['aa'.'bb'.'cc'].// Multiple columns, in order
data: [{values: ['1'.'2'.'3'] {},values: [1-1 ' '.'2'.'1-3'] {},values: ['1-1-1'.'1-1-2'.'1-1-3']}]Copy the code
Fill in the data

Now that you have a basic three-column selector, the next step is to populate the data

// These three data are returned by the cache interface
let _provinceList = []
let _cityList = []
let _districtList = []
// This data is used to determine whether picker's data exists
let __pickerDataInit__ = false
// These three data are used to get the index of the currently selected province
let __selectProvinceId__ = 0
let __selectCityId__ = 0
let __selectDistrictId__ = 0

/ / get province
getProvince() {
    // Interface interaction
    Res. data is the data returned by the interface
    // Cache a copy first, because the data returned by the interface is different from the data required by van-picker
    {id=xx, name='xx'}
    _provinceList = res.data
    // Get the reasonable data, put it directly into data, the first column is province
    this.setData({
        "data[0].values": _parse2VanPickerData(res.data)
    })
    __pikcerDataInit__ = true
}

/ / for the city
getCity(provinceId) {
    // The interface needs provinceId to get cities
    Res. data is the data returned by the interface
    // Cache a copy
    _cityList = res.data
    this.setData({
        "data[1].values": _parse2VanPickerData(res.data)
    })
    // The market can be retrieved directly from the market, since the market can be retrieved simultaneously from the market
    this.getDistrict(_districtList(__selectDistrictId__))
}

/ / access area
getDistrict(cityId) {
    // The interface needs to use provinceId to fetch a districts
    Res. data is the data returned by the interface
    _districtList = res.data
    this.setData({
        "data[2].values": _parse2VanPickerData(res.data)
    })
}

// Open popUp for the selected province
showPopup() {
    this.setData({
        popUpShow: true
    })
    // Get data
    this.getProvince()
    if(! __pickerDataInit__){// No data available yet
       // We want to initialize the data to display the first district of the first city of the first province
       this.getProvince()
       this.getCity(_cityList[__selectCityId__].id))
    }
}

function _parse2VanPickerData(arr) {
    let res = []
    arr.forEach(item= > {
        res.push(item)
    })
    return res
}
Copy the code
Switch options

Next, is the most critical, switch when the three linkage

<! -- bind:change van-picker -->
<van-picker id="picker" column="{{pickerColumnData}}" bind:change="onPickerChange" />
Copy the code
Index is the next table to which the column is currently switched. For example, if you slide the first column, it is 0, and the second column, it is 1
// Get the picker instance through selectComponent. There is a method getIndexs that gets all the subscripts for the three groups
onPickerChange(e) {
    // Get the current subscript s
    const currentIndexs = this.selectComponent('#picker').getIndexes()
    // Determine which of the three slides is used
    switch (e.detail.index) {
      case 0:
        // If it is the first one, we get the id of the province and the cities under the province
        const provinceId = PROVINCE_LIST[currentIndexs[0]].id
        __selectProvinceIndex__ = currentIndexs[0]
        this.getCityList(provinceId)
      case 1:
        // If you slide the city, get the region under the city
        const cityId = CITY_LIST[currentIndexs[1]].id
        this.getDistrictList(cityId)
        __selectCityIndex__ = currentIndexs[1]}}Copy the code
Complete choice
onPickerConfirm() {
    // The selection is complete
    const currentIndexs = this.selectComponent('#picker').getIndexes()
    // Get the name and ID of the selected province
    const province = PROVINCE_LIST[currentIndexs[0]]
    const city = CITY_LIST[currentIndexs[1]]
    const district = DISTRICT_LIST[currentIndexs[2]]
    this.setData({
      // The provincial id is passed to the backend when it needs to be added
      addProvinceId: province.id,
      addCityId: city.id,
      addDistrictId: district.id,
      // This is the front display, only show the name of the province, put together
      addFormAreaValue: province.name + city.name + district.name,
      // defaultIndex: the index selected by province by default
      // The main effect of this is: if you press the wrong button, come back to the same place you just selected
      "data[0].defaultIndex": currentIndexs[0]."data[1].defaultIndex": currentIndexs[1]."data[2].defaultIndex": currentIndexs[2].// Finally close popup
      popupShow: false})},Copy the code

At this point, the process is probably over

The final result

To optimize the

1. loading

<! -- Van-picker has a property loading that can be loaded on request -->
<van-picker loading="{{pickerLoading}}"></van-picker>
Copy the code

2. Initialize global variables

Remember to initialize global variables in onUnload

onUnload() {
  let _provinceList = []
  let _cityList = []
  let _districtList = []
  let __pickerDataInit__ = false
  let __selectProvinceId__ = 0
  let __selectCityId__ = 0
  let __selectDistrictId__ = 0
}
Copy the code