评论

如何实现一个自定义数据版省市区三级联动

自定义数据版本省市区三级联动,可自行扩展为二级联动

刚有老哥问为啥iPhone 11 不支持省市区三级联动,然后让老哥提供了个代码片段。我用iPhone X看了下 也跑不起来啊。看了下代码逻辑,只有一个省,只写了一个picker-view-column,这搞个啥三级联动。。。然后老哥说了是抠了一部分代码出来的。既然有问题,那我们还是那句话,有需求,然后能搞出来的,咱就花点时间去搞。

然后给老哥实现了该功能,社区可能有其他的方案了,但是再分享下吧,给有需要的童鞋。

效果图:

额,这个视频转GIF因为社区上传不了大图,所以剪了一部分,具体的效果还是直接工具打开代码片段预览吧~

上代码

wxml:

<view class="address-item" bindtap="pickAddress">
  <view class="item-title">所在地区</view>
  <view class="item-content arrow {{region ? '' : 'item-content_shadow'  }}">{{region||"请选择"}}</view>
</view>
<pop-up visible="{{visible}}" onClose="closePopUp">
  <view slot="content">
    <view class="picker-view">
      <view class="picker-view__pane">
        <text catchtap="cityCancel">取消</text>
        <text catchtap="citySure">确定</text>
      </view>
      <picker-view class="pick-view__group" bindchange="cityChange" value="{{value}}" bindpickstart="chooseStart" bindpickend="chooseEnd">
        <picker-view-column indicator-class="item_active">
          <view wx:for="{{provinces}}" class="picker-item" wx:key="idnex">{{item.name}}</view>
        </picker-view-column>
        <picker-view-column>
          <view wx:for="{{citys}}" class="picker-item" wx:key="">{{item.name}}</view>
        </picker-view-column>
        <picker-view-column>
          <view wx:for="{{areas}}" class="picker-item" wx:key="">{{item.name}}</view>
        </picker-view-column>
      </picker-view>
    </view>
  </view>
</pop-up>

这里有封装一个自定义组件pop-up,是从下往上弹出的的一个效果,已放到代码片段里了,自行查看即可~

接下来是wxss

.address-item {
  min-height: 98rpx;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  border-bottom: 1px solid #f1f1f1;
}

.item-title {
  width: 203rpx;
  color: #4d4c4c;
  font-size: 28rpx;
  height: 98rpx;
  line-height: 98rpx;
}
.item-content {
  width: 520rpx;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 28rpx;
  height: 98rpx;
  line-height: 98rpx;
  color: #4d4c4c;
}
/* 地区级联选择器 */

.picker-view {
  width: 100%;
  display: flex;
  background-color: #fff;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  bottom: 0rpx;
  left: 0rpx;
}

.picker-item {
  line-height: 70rpx;
  margin-left: 5rpx;
  margin-right: 5rpx;
  text-align: center;
}

.picker-view__pane {
  height: 100rpx;
  width: 100%;
  padding: 20rpx 32rpx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-sizing: border-box;
}

.picker-view__pane text{
  color: red;
  font-size: 30rpx;
}

.pick-view__group {
  width: 96%;
  height: 450rpx;
}

呐,接下来还是重点的js处理。

首先我在本地定义了一个city.js,网上下载的。主要是省市区的数据

var provinces = [{
  "name": "北京市",
  "id": "110000"
}, {
  "name": "天津市",
  "id": "120000"
}, {
  "name": "河北省",
  "id": "130000"
}, {
  "name": "山西省",
  "id": "140000"
}, {
  "name": "内蒙古自治区",
  "id": "150000"
}, {
  "name": "辽宁省",
  "id": "210000"
}]

就不放太多了,具体的可以在代码片段里查看,大家可以自定义数据的id,贴合自己的业务场景。

然后是页面js处理

var app = getApp()
var address = require('./city.js')

var app = getApp()
Page({
  data: {
    address: '', //详细收货地址(四级)
    value: [0, 0, 0], // 地址选择器省市区 暂存 currentIndex
    region: '', //所在地区
    regionValue: [0, 0, 0], // 地址选择器省市区 最终 currentIndex
    provinces: [], // 一级地址
    citys: [], // 二级地址
    areas: [], // 三级地址
    visible: false,
    isCanConfirm: true //是否禁止在第一列滚动期间点击确定提交数据
  },
  onLoad(options) {
    // 默认联动显示北京
    var id = address.provinces[0].id 
    this.setData({
      provinces: address.provinces, // 34省
      citys: address.citys[id], //默认北京市辖区
      areas: address.areas[address.citys[id][0].id]
    })
  },
  closePopUp() {
    this.setData({
      visible: false
    })
  },
  pickAddress() {
    this.setData({
      visible: true,
      value: [...this.data.regionValue]
    })
  },
  // 处理省市县联动逻辑 并保存 value
  cityChange(e) {
    var value = e.detail.value
    let {
      provinces,
      citys
    } = this.data
    var provinceNum = value[0]
    var cityNum = value[1]
    var areaNum = value[2]

    if (this.data.value[0] !== provinceNum) {
      var id = provinces[provinceNum].id
      this.setData({
        value: [provinceNum, 0, 0],
        citys: address.citys[id],
        areas: address.areas[address.citys[id][0].id]
      })
    } else if (this.data.value[1] !== cityNum) {
      var id = citys[cityNum].id
      this.setData({
        value: [provinceNum, cityNum, 0],
        areas: address.areas[citys[cityNum].id]
      })
    } else {
      this.setData({
        value: [provinceNum, cityNum, areaNum]
      })
    }
  },
  preventTouchmove() {},
  // 城市选择器
  // 点击地区选择取消按钮
  cityCancel(e) {
    var id = address.provinces[0].id 
    this.setData({
      citys: this.data.lastCitys ||  address.citys[id], //默认北京市辖区,
      areas: this.data.lastAreas || address.areas[address.citys[id][0].id],
      value: [...this.data.regionValue],
      visible: false
    })
  },
  // 提交时由序号获取省市区id
  getRegionId(type) {
    let value = this.data.regionValue
    let provinceId = address.provinces[value[0]].id
    let townId = address.citys[provinceId][value[1]].id
    let areaId = ''
    if (address.areas[townId][value[2]].id) {
      areaId = address.areas[townId][value[2]].id
    } else {
      areaId = 0
    }

    if (type === 'provinceId') {
      return provinceId
    } else if (type === 'townId') {
      return townId
    } else {
      return areaId
    }
  },
  chooseStart(e) {
    this.setData({
      isCanConfirm: false
    })
  },
  chooseEnd(e) {
    this.setData({
      isCanConfirm: true
    })
  },
  // 点击地区选择确定按钮
  citySure(e) {
    if (this.data.isCanConfirm) {
      var value = this.data.value
      this.setData({
        visible: false
      })
      // 将选择的城市信息显示到输入框
      try {
        var region = (this.data.provinces[value[0]].name || '') + (this.data.citys[value[1]].name || '')
        if (this.data.areas.length > 0) {
          region = region + this.data.areas[value[2]].name || ''
        } else {
          this.data.value[2] = 0
        }
      } catch (error) {
        console.log('adress select something error')
      }
  
      this.setData({
        region: region,
        lastCitys: this.data.citys,
        lastAreas: this.data.areas,
        regionValue: [...this.data.value]
      }, () => {
        console.log(`省份ID:${this.getRegionId('provinceId')}: 市区ID:${this.getRegionId('townId')}:城区ID:${this.getRegionId('areas')}`)
      })
    }
  }
})

以上就是一个自定义数据版本的省市区三级联动啦,老规矩,结尾放代码片段,大家可自行修改代码扩展,可改为二级联动等。

https://developers.weixin.qq.com/s/dvdxfSml7BhT

最后一次编辑于  2020-07-06  
点赞 38
收藏
评论

17 个评论

  • 九块腹肌的猛男
    九块腹肌的猛男
    2020-06-05

    20200605 修复picker第一列滑动过快还未暂停就点击确定,输出异常的问题。

    2020-06-05
    赞同 3
    回复
  • @陳
    @陳
    2020-01-17

    picker滚动到别的省份,然后点击取消,再显示的话会出错

    2020-01-17
    赞同 1
    回复 1
  • chen
    chen
    2020-12-31

    大佬省市区的数据还有吗可以分享一下吗

    2020-12-31
    赞同
    回复 1
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-12-31
      代码片段里有。我有单独弄一个js文件。你打开代码片段可以看到。
      2020-12-31
      回复
  • 一蓑烟雨
    一蓑烟雨
    2020-07-14

    大佬,我用你的原生文件复制了下,我更改了index也为组件,然后把index(里面有pop-up组件),拿到页面显示,,页面显示不出选择的数据.

    2020-07-14
    赞同
    回复 6
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-07-14
      搞个代码片段发我。
      2020-07-14
      3
      回复
    • 一蓑烟雨
      一蓑烟雨
      2020-07-14回复九块腹肌的猛男
      代码全用你上传的那个代码,就是把里面的index页面文件改为组件文件了,然后在页面里面用index这个组件,代码一点没动.
      2020-07-14
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-07-14回复一蓑烟雨
      你用我写的代码片段。改造成你现在这样然后发我。我给你改下。
      2020-07-14
      3
      回复
    • 一蓑烟雨
      一蓑烟雨
      2020-07-14回复九块腹肌的猛男
      我没改你的代码,就是把index这个文件,我改为了组件,然后放到页面使用,就变成上面图片那样了,代码一点没动.
      2020-07-14
      回复
    • 一蓑烟雨
      一蓑烟雨
      2020-07-14回复一蓑烟雨
      我知道问题在哪了,页面传值到组件那里,组件和组件传值我还没设置,麻烦大佬了!
      2020-07-14
      回复
    查看更多(1)
  • 阿飞
    阿飞
    2020-06-17

    选到最后一个就报错了

    2020-06-17
    赞同
    回复 5
  • 🔅曲水
    🔅曲水
    2020-06-04

    请问数据回显怎么做呀。需求是编辑的时候,需要回显之前选择的省市区。

    2020-06-04
    赞同
    回复 9
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-04
      弹起来的时候需要自动选择 之前选择的是吗?
      2020-06-04
      3
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-04
      需要知道之前选择省市区的code。在onLoad的时候进行回填即可。
      2020-06-04
      3
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-04
      2020-06-04
      2
      回复
    • 🔅曲水
      🔅曲水
      2020-06-04回复九块腹肌的猛男
      基本上是这样,不过还有一个场景是,组件已经加载完成了,此时再塞值给组件,回显省市区。
      如图,选择乙方全称后,带出公司地址,做回显。
      2020-06-04
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-04回复🔅曲水
      那你可以重新赋值一遍就好了呀
      2020-06-04
      3
      回复
    查看更多(4)
  • Baymax
    Baymax
    2020-06-01

    我这块 修改了一下,然后默认显示北京,在点击北京就是空的,如果选择了别的城市,在选择北京 才可以,大佬有时间的时候,麻烦指导下

    2020-06-01
    赞同
    回复 6
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-01
      具体是指?需要默认展示北京是么?
      2020-06-01
      3
      回复
    • Baymax
      Baymax
      2020-06-01回复九块腹肌的猛男
      把你的原版代码撸下来,按照我的需求做了部分改动,现在是默认展示的是北京,但是点开picker选择北京就是空的,如果先选择了别的城市在选择北京,才会显示
      2020-06-01
      1
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-01回复Baymax
      改动的代码能贴个代码片段么??
      2020-06-01
      3
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-01回复Baymax
      你现在想实现什么样式。我看下我能不能给你改。
      2020-06-01
      4
      回复
    • Baymax
      Baymax
      2020-06-02回复九块腹肌的猛男
      问题已修复,感谢大佬
      2020-06-02
      回复
    查看更多(1)
  • Rick
    Rick
    2020-05-28

    请问选中的文字,颜色可以自定义吗?如何自定义呢

    2020-05-28
    赞同
    回复 5
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-05-28
      选中的文字??是指点确定后的还是 下面滚动区域的文字
      2020-05-28
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-02
      2020-06-02
      3
      回复
    • Baymax
      Baymax
      2020-06-02
      谢谢大佬,
      2020-06-02
      回复
    • Rick
      Rick
      2020-06-02回复九块腹肌的猛男
      大佬啊(捂脸),最近一直在忙,都没看到你回复我了,而且还回复了代码,真是感谢啊!!!XD
      2020-06-02
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-06-02回复Rick
      2020-06-02
      1
      回复
  • YL
    YL
    2020-05-06

    很棒。非常感谢

    2020-05-06
    赞同
    回复
  • 信仰2
    信仰2
    2020-04-14

    不知道为毛帖子收藏不了

    2020-04-14
    赞同
    回复 11
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-04-14
      可以呀。
      2020-04-14
      2
      回复
    • 信仰2
      信仰2
      2020-04-14回复九块腹肌的猛男
      你好 想问问在哪里可以初始化这个picker呢 比如我一进来要选择广东省广州市白云区
      2020-04-14
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-04-14回复信仰2
      onLoad里哈。
      2020-04-14
      1
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-04-14回复信仰2
      onLoad(options) {
          // 默认联动显示北京
          var id = address.provinces[18].id 
          this.setData({
            provinces: address.provinces, // 34省
            citys: address.citys[id], //默认北京市辖区
            areas: address.areas[address.citys[id][0].id],
            value: [18, 0, 5],
            regionValue: [18, 0, 5],
          })
        },
      2020-04-14
      3
      回复
    • 九块腹肌的猛男
      九块腹肌的猛男
      2020-04-14
      18,0,5是广东广州白云区的下标。这个可以在你选择后 appData的value里查看。
      2020-04-14
      2
      回复
    查看更多(6)

正在加载...

登录 后发表内容