微信小程序三级联动,省市区联动组件封装

前言

微信小程序省市区三级联动,原生局限性太大,自己用picker-view,picker-view-column重新封装自定义组件,

功能展示

在这里插入图片描述

把数据过滤为 picker-view 展示数组

请添加图片描述
解析树形结构数组对象,跟据下标集遍历子项列表
请添加图片描述
我的思路是根据下标集遍历数组对象,子项递归

// 根据下标数组,遍历树结构,子项单独数组(arr:遍历数组,arr1下标数组,初始遍历层级)
    filterChild : function (arr:any,arr1:any,index:number) {
      let listKey = this.properties.listKey;
      var result = arr1 as any;
      for (var i = 0, len = arr1.length; i < len; i++) {
        if (index === i) {
          // 获取该层级已选下标
          let _i = arr1[i];
          // 第一个层级数组获取全部
          let _arr = [] as any;
          // 递归树结构
          for (var j = 0, len1 = arr.length; j < len1; j++) {
              // 默认取下标第一个
              _arr.push(arr[j])
              // 对应已选下标进行后续递归
              if (_i == j) {
                // children后续数组长度比已选下标小,归0
                let _j = _i < arr.length - 1 ? _i : 0;
                let _list = arr[_j][listKey]
                if (Array.isArray(_list)) {
                  this.filterChild(_list,arr1,++index)
                  result[index]=_list
                }
              }
          }
          result[0] = _arr
        }
      }
      return result;
    },

点击确认返回已选对象

 _onConfirm: function () {
      const {pickerList,pickerListI} = this.data;
      let listCur = [] as any;
      // 返回已选项
      pickerListI.forEach((item,index) => {
         let obj = pickerList[index][item] || {};
         if (JSON.stringify(obj) !== '{}') {
          listCur.push(obj)
         }
      })
      this.triggerEvent('onConfirm',listCur)
      this._onClose()
    },

请添加图片描述

wxml文件

<!--components/pickerView/pickerView.wxml-->
<!--
	customStyle 自定义css样式
  isPicker:是否显示
  listCur:下标集
  listKey:遍历keys,默认children 
  keys:要展示的字段,默认value
-->
<view class="picker">
  <!-- 多级选择弹框 -->
  <view class="picker-cont" wx:if="{{isPicker}}">
    <!-- 背景 -->
    <view class="bg" bindtap="_onClose"></view>
    <!-- 内容 -->
    <view class="cont" style="{{customStyle}}">
      <view class="picker-box">
        <picker-view  class="picker-view" value="{{ pickerListI }}"  bindchange="_onChange">
            <picker-view-column wx:for="{{pickerList}}" wx:key="picker" >
              <view class="picker-view-column" wx:for="{{item}}" wx:for-item="item1" wx:key="pickerItem">{{item1[keys]}}</view>
            </picker-view-column>
        </picker-view>
      </view>
      <view class="btn-box">
        <text class=" btn btn-1" bindtap="_onClose">取消</text>
        <view class="btn" bindtap="_onConfirm">确认</view>
      </view>
    </view>
  </view>
</view>

scss文件

/* components/pickerView/pickerView.wxss */
.picker{
  width: 100%;
  height: 100vh;
  overflow: hidden;
  position: relative;
}

.picker-cont{
  position: absolute;
  left: 0;
  bottom: 0;
  overflow: hidden;
  width: 100%;
  height: 100vh;
  z-index: 8;
  .bg{
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100vh;
    background: rgba(0, 0, 0, .5);
    z-index: 10;
  }
  .cont{
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 460rpx;
    z-index: 12;
    background: #FFF;
    .picker-box{
      display:flex;
      width: 100%;
      height: calc(100% - 100rpx);
      .picker-view {
        width: 100%;height: 100%;text-align: center;
      }
      .picker-view-column {
        height: 34px;
        line-height: 34px;
      }
    }
    .btn-box{
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100rpx;
      line-height: 100rpx;
      padding: 0 20rpx;
      box-sizing: border-box;
      border-bottom: 1px solid #EEE;
    }
    .btn-box .btn {
      width: 180rpx;
      height: 56rpx;
      line-height: 56rpx;
      background: linear-gradient(180deg, #FFDF0F 0%, #FFF336 100%);
      border-radius: 8rpx;
      color: #333;
      text-align: center;
    }
    .btn-box .btn-1 {
      background: #ccc;
      color: #fff;
      margin-right: 30rpx;
    }
  }
  
}

ts文件

// components/pickerView/pickerView.ts
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    isPicker: {
      type: Boolean,
      value: true
    },
    // 树结构数组
    list: {
      type: Array,
      value:[]
    },
    // 下标集
    listCur: {
      type: Array,
      value:[]
    },
    // 列表遍历的keys
    listKey: {
      type:String,
      value: 'children'
    },
    // 展示字段名
    keys: {
      type:String,
      value: 'value'
    },
    customStyle: {
      type:String,
      value: ''
    }
  },
  lifetimes: {
    ready() {
      let list = this.properties.list || [];
      let listCur = this.properties.listCur || [];
      if (list.length == 0) return
      // 下标集,没传初始化
      let pickerListI = listCur.length ? listCur : this.filter(list);
      // 跟据下标数组进行遍历
      let pickerList = this.filterChild(list,pickerListI,0)
      this.setData({
        list: this.properties.list,
        pickerList,
        pickerListI:this.filter(list),
      })
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    // 弹窗
    isPicker: false,
    // 原数据
    list: [] as any,
    // 过滤后数组
    pickerList: [] as any,
    // 已选下标数组
    pickerListI: [],
  },

  /**
   * 组件的方法列表
   */
  methods: {
    // 递归数组获取总层级数,并初始化下标
    filter: function (arr:any) {
      var result = []as any;
      for (var i = 0, len = arr.length; i < len; i++) {
        if(i==0) {
          result.push(0)
          if (Array.isArray(arr[i].s)) {
              result = result.concat(this.filter(arr[i].s))
          } 
        }
      }
      return result;
    },
    // 根据下标数组,遍历树结构,子项单独数组(arr:遍历数组,arr1下标数组,初始遍历层级)
    filterChild : function (arr:any,arr1:any,index:number) {
      let listKey = this.properties.listKey;
      var result = arr1 as any;
      for (var i = 0, len = arr1.length; i < len; i++) {
        if (index === i) {
          // 获取该层级已选下标
          let _i = arr1[i];
          // 第一个层级数组获取全部
          let _arr = [] as any;
          // 递归树结构
          for (var j = 0, len1 = arr.length; j < len1; j++) {
              // 默认取下标第一个
              _arr.push(arr[j])
              // 对应已选下标进行后续递归
              if (_i == j) {
                // children后续数组长度比已选下标小,归0
                let _j = _i < arr.length - 1 ? _i : 0;
                let _list = arr[_j][listKey]
                if (Array.isArray(_list)) {
                  this.filterChild(_list,arr1,++index)
                  result[index]=_list
                }
              }
          }
          result[0] = _arr
        }
      }
      return result;
    },
    // 关闭多级选择器
    _onClose: function () {
      this.setData({
        isPicker: false
      })
    },
    // 打开多级选择器
    _onConfirm: function () {
      const {pickerList,pickerListI} = this.data;
      let listCur = [] as any;
      // 返回已选项
      pickerListI.forEach((item,index) => {
         let obj = pickerList[index][item] || {};
         if (JSON.stringify(obj) !== '{}') {
          listCur.push(obj)
         }
      })
      this.triggerEvent('onConfirm',listCur)
      this._onClose()
    },
    _onChange: function (e:any) {
      const val = e.detail.value;
      let list = this.data.list;
      // 复制数组,防止污染
      let _val = JSON.parse(JSON.stringify(val));
      let pickerList = this.filterChild(list,_val,0)
        this.setData({
          pickerList,
          pickerListI:val
        })
    },
  }
})

使用

引用组件pickerView

<view class="">
  <pickerView isPicker="true" keys="n" list="{{city}}" listKey="s" bind:onConfirm="onConfirm" ></pickerView>
</view>


onConfirm(e) {
    let listCur = e.detail || [];
    console.log(listCur);
  },

总结

挺常见的多级联动,目前只用了省市区三级联动 ,别的场景暂时没测试,优化暂时没有
最后欢迎大家点赞,收藏

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信小程序三级联动懒加载是指在选择上一级选项后,动态加载下一级选项的功能。通过使用picker-view组件,我们可以实现这一功能。在picker-view组件中,我们可以通过绑定bindchange事件来监听选择的变化,在事件处理函数中,可以根据选择的上一级选项的值来动态生成下一级选项的数据,并更新picker-view的range属性。这样就可以实现在选择上一级选项后,自动加载下一级选项的效果。 下面是一个示例代码,展示了如何实现微信小程序三级联动懒加载: ``` <picker-view bindchange="bindPickerChange" value="{{value}}" range="{{range}}" bindcolumnchange="bindColumnChange"> <picker-view-column> {{range[0]}} </picker-view-column> <picker-view-column> {{range[1]}} </picker-view-column> <picker-view-column> {{range[2]}} </picker-view-column> </picker-view> Page({ data: { value: [0, 0, 0], range: [[], [], []] }, onLoad: function () { // 初始化第一级选项的数据 // 通过请求接口获取数据,并更新this.data.range[0]的值 }, bindPickerChange: function (e) { const column = e.detail.column; const value = e.detail.value; const range = this.data.range; if (column === 0) { // 根据选择的第一级选项的值,动态生成第二级选项的数据 // 通过请求接口获取数据,并更新range[1]的值 } else if (column === 1) { // 根据选择的第二级选项的值,动态生成第三级选项的数据 // 通过请求接口获取数据,并更新range[2]的值 } this.setData({ value: value, range: range }); }, bindColumnChange: function (e) { const column = e.detail.column; const value = e.detail.value; const range = this.data.range; if (column === 0) { // 根据选择的第一级选项的值,动态生成第二级选项的数据 // 通过请求接口获取数据,并更新range[1]的值 } else if (column === 1) { // 根据选择的第二级选项的值,动态生成第三级选项的数据 // 通过请求接口获取数据,更新range[2]的值 } this.setData({ range: range }); } }); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值