这两天在写公司小程序项目的时候,需要使用级联选择器,并且要支持模糊和新增功能,然后我就去看了下uview组件库和uni的拓展组件中的级联选择器,功能都非常简,不能满足当前的需求... 接下来我就分享一下我完成该需求整体流程和思路...
实现功能:
1. 点击右侧箭头可以对所有级联数据进行选择
2. 输入框输入内容实现级联数据的模糊搜索,搜索后对筛选的级联数据进行选择
这里我先粘一下结构代码
// 表单部分
<view class="formitem-left">
<u--input ref="goodsIpt" placeholder="请选择运输货物" border="surround"
v-model="pageData.goodsName" @input="goodsInput"></u--input>
</view>
<view @click="chooseGoodsName">
<u-icon :name="rightIcon" color="#999"></u-icon>
</view>
// 级联选择器
<u-picker ref="goodsNameRef" :show="showGoodsNamePic" :columns="goodsNameCol" :loading="goodsNameLoading" @confirm="confirmGoodsName" @cancel="cancelGoodsName" @change="changeGoodsName"></u-picker>
处理级联选择器 选择的相关逻辑 (改组件需要自己去处理该逻辑)
changeGoodsName(e) {
const {
columnIndex,
value,
values, // values为当前变化列的数组内容
index,
// 微信小程序无法将picker实例传出来,只能通过ref操作
picker = this.$refs.goodsNameRef
} = e
console.log(columnIndex, 'columnIndex');
console.log(value, 'value');
console.log(values, 'values');
console.log(index, 'index');
if (columnIndex === 0) {
let item = this.seaRchGoodsNameData.find(item => item.name == value[0])
if (item.children && item.children.length) {
let colTwo = item.children.map(item => item.name)
let colThree = []
if (item.children[0].children && item.children[0].children.length) {
colThree = item.children[0].children.map(item => item.name)
}
picker.setColumnValues(1, colTwo)
picker.setColumnValues(2, colThree)
} else {
picker.setColumnValues(1, [])
picker.setColumnValues(2, [])
}
}
if (columnIndex === 1) {
let itemFa = this.seaRchGoodsNameData.find(item => item.name == value[0]).children
let item = itemFa.find(item => item.name == value[1])
if (item.children && item.children.length) {
let colThree = item.children.map(item => item.name)
picker.setColumnValues(2, colThree)
} else {
picker.setColumnValues(2, [])
}
}
}
在watch中对级联选择器显示所需要的数据进行处理 (对每一级数据都进行判断处理)
seaRchGoodsNameData: {
handler() {
if (!this.seaRchGoodsNameData.length) return this.goodsNameCol = []
let idxOne = this.seaRchGoodsNameData.map(item => item.name)
if (!this.seaRchGoodsNameData[0].children || !this.seaRchGoodsNameData[0].children.length) return this
.goodsNameCol = [idxOne, [],
[]
]
let idxTwo = this.seaRchGoodsNameData[0].children.map(item => item.name)
if (!this.seaRchGoodsNameData[0].children[0].children || !this.seaRchGoodsNameData[0].children[0]
.children.length) return this.goodsNameCol = [idxOne,
idxTwo, []
]
let idxThree = this.seaRchGoodsNameData[0].children[0].children.map(item => item.name)
return this.goodsNameCol = [idxOne, idxTwo, idxThree]
},
deep: true,
immediate: true
}
到这里以及可以实现级联选择器的显示了,接下来就是去处理级联数据的模糊搜索...
首先定义下模糊搜索的方法,实现可以对每一级数据的模糊搜索进行不同的处理
goodsNameSearch(text, index) {
let curText = text.toLowerCase()
if (index == 1) {
if (curText) {
let arr = JSON.parse(JSON.stringify(this.goodsNameData)).filter(item => item.name.toLowerCase()
.indexOf(curText) !== -1)
if (arr.length) {
this.seaRchGoodsNameData = arr
} else {
this.seaRchGoodsNameData = []
}
} else {
this.seaRchGoodsNameData = this.goodsNameData
}
}
if (index == 2) {
if (curText) {
this.seaRchGoodsNameData.forEach(item => {
if (item.children) {
let arr = item.children.filter(item => item.name.toLowerCase().indexOf(curText) !==
-1)
if (arr.length) {
item.children = arr
} else {
item.children = []
}
}
})
}
}
if (index == 3) {
if (curText) {
this.seaRchGoodsNameData.forEach(itemFa => {
itemFa.children.forEach(item => {
if (item.children) {
let arr = item.children.filter(item => item.name.toLowerCase().indexOf(
curText) !==
-1)
if (arr.length) {
item.children = arr
} else {
item.children = []
}
}
})
})
}
}
},
上述代码就是模糊搜索方法中所涉及到的所以代码,在这里我没有对代码做优化处理,你们使用的过程中,可自行处理。
接下来,就是对输入的值进行分级次处理,并调用模糊搜索的方法...
goodsInput(val) {
let valArr = val.split('')
let length = valArr.filter(item => item == '/').length
if (this.goodsTimer) clearTimeout(this.goodsTimer)
this.goodsTimer = setTimeout(() => {
if (!val) {
this.seaRchGoodsNameData = this.goodsNameData
}
if (!length && valArr[0] != '/') {
this.goodsNameSearch(val, 1)
}
if (length && valArr[0] == '/') {
this.seaRchGoodsNameData = []
}
if (length == 1 && valArr[0] != '/') {
const arr = val.split('/')
const valOne = arr[0]
const valTwo = arr[1]
if (!valOne.length) {
this.seaRchGoodsNameData = []
}
if (valOne.length) {
this.goodsNameSearch(valOne, 1)
}
if (valTwo.length && this.seaRchGoodsNameData.length) {
this.goodsNameSearch(valTwo, 2)
}
}
if (length == 2 && valArr[0] != '/') {
const arr = val.split('/')
const valOne = arr[0]
const valTwo = arr[1]
const valThr = arr[2]
if (!valOne.length) {
this.seaRchGoodsNameData = []
}
if (valOne.length) {
this.goodsNameSearch(valOne, 1)
}
if (valTwo.length && this.seaRchGoodsNameData.length) {
this.goodsNameSearch(valTwo, 2)
}
if (valThr.length && this.seaRchGoodsNameData.length) {
this.goodsNameSearch(valThr, 3)
}
}
this.showGoodsNamePic = true
this.$refs.goodsIpt.focus = false
uni.hideKeyboard()
}, 2200)
}
到这里已经可以实现数据的模糊搜索了,接下来就是分别对确认和取消选择操作进行相关处理...
首先看下确认操作
confirmGoodsName(val) {
console.log(val.value, '----');
console.log(val.value.join('/'), '++++');
let arr = val.value
if (arr[1] === undefined) {
arr.splice(1)
} else if (arr[2] === undefined) {
arr.splice(2, 1)
}
let colOneIndex = ''
let colTwoIndex = ''
let idArr = arr.map((item,index) => {
if(index ==0) {
let colOneItem = this.seaRchGoodsNameData.find(val => val.name == item)
colOneIndex = this.seaRchGoodsNameData.findIndex(val => val.name == item)
return colOneItem.id
} else if(index == 1) {
let colTwoItem = this.seaRchGoodsNameData[colOneIndex].children.find(val => val.name == item)
colTwoIndex = this.seaRchGoodsNameData[colOneIndex].children.findIndex(val => val.name == item)
return colTwoItem.id
} else if(index == 2) {
let colThrItem = this.seaRchGoodsNameData[colOneIndex].children[colTwoIndex].children.find(val => val.name == item)
return colThrItem.id
}
})
this.pageData.goodsName = arr.join('/')
this.pageData.goodsNameArr = arr
this.pageData.goodsNameId = idArr
this.showGoodsNamePic = false
}
通过级联选择器所得到的名称数据,得到其对应的id数组,并存储名称数组用于取消操作中的比较...
最后我们看下取消操作,防止用户不进行选择,导致di缺失的问题...
cancelGoodsName() {
let curArr = this.pageData.goodsName.split('/')
let TargetArr = this.pageData.goodsNameArr
if(curArr.length != TargetArr.length) {
this.pageData.goodsName = ''
}
curArr.forEach((item,index) => {
if(item != TargetArr[index]) this.pageData.goodsName = ''
})
this.showGoodsNamePic = false
}
到这里,功能就基本实现了,代码纯手写,喜欢的可以给个star...