前言
微信小程序省市区三级联动,原生局限性太大,自己用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);
},
总结
挺常见的多级联动,目前只用了省市区三级联动 ,别的场景暂时没测试,优化暂时没有
最后欢迎大家点赞,收藏