uniapp自定义级联多选下拉框
工作时遇到的级联多选下拉框需求,由于寻找多方的uniapp第三方库都没找到合适的ui组件,所以用css+js自己写了一个。废话不多说,先看效果,然后直接上代码(因为业务需求单一,所以配置项直接写在组件内,需要改动的小伙伴请自己动手哦!)。
效果如下
代码如下
<template>
<view class="select">
<view class="value-box" @click="openOptions">
<view v-if="value.length!=0" class="item-list">
<view class="item font-active-color">
<view v-for="item in list" class="item-value">
<view>{{item}}</view>
<uni-icons type="clear" color="gray" @click.native.stop="del(item)"></uni-icons>
</view>
</view>
</view>
<view v-else class="item font-init-color">请输入日期</view>
<uni-icons type="arrowup" v-if="status==0" class="icon"></uni-icons>
<uni-icons type="arrowdown" class="icon" v-else></uni-icons>
</view>
<view class="box" v-if="status==1">
<view class="opration">
<view class="cancel" @click="cancel">取消</view>
<view class="confirm" @click="confirm">确定</view>
</view>
<view class="data-options">
<view class="left-content">
<view v-for="(item,index) in leftList" class="year-box"
:class="yearIndex==index ? 'active':'default'" @click="getIdx(item,index)">
{{item.year}}
</view>
</view>
<view class="right-content">
<view v-for="item in rightList" class="month-box" :class="item.status==1 ? 'active':'default'"
@click="changeStatus(item)">{{item.month}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
status: 0,
leftList: [], //下拉列表右边
rightList: [], //下拉列表左边
yearIndex: 0,
timeList: [], //整体下拉列表
list: [], //组件内的数据
}
},
props: {
//传入的数据
value: {
type: Array,
default: () => []
}
},
watch: {
list() {
this.reset();
}
},
mounted() {
this.list = this.value;
this.initTimeList();
},
methods: {
/**
* 删除选中的值
* @param item 元素值
*/
del(item) {
this.list.forEach((e, index) => {
if (e == item) {
this.list.splice(index, 1);
}
})
this.$emit('input', this.list);
},
/**
* 选中下拉框里的值赋值
*/
confirm() {
let result = [];
this.timeList.forEach(item => {
if (item.status == true) {
result.push(item.key);
}
})
this.list.forEach(v=>{
if(v<this.timeList[0].key){
result.unshift(v)
}
})
this.list = result;
this.status = false;
this.$emit('input', this.list);
},
/**
* 关闭下拉框
*/
cancel() {
this.status = false;
},
/**
* 激活当前年份
* @param item 元素 @param index 索引
*/
getIdx(item, index) {
this.rightList = [];
this.yearIndex = index;
this.timeList.forEach(v => {
if (v.year == item.year) {
this.rightList.push(v);
}
})
},
/**
* 初始化下拉框
*/
initTimeList() {
this.leftList = [];
let year = new Date().getFullYear();
for (let i = 0; i < 10; i++) {
let obj = {};
obj.year = year - 10 + i
this.leftList.push(obj);
for (let j = 0; j < 12; j++) {
let obj = {};
if (j + 1 < 10) {
obj.month = '0' + Number(j + 1);
} else {
obj.month = j + 1;
}
obj.status = false;
obj.year = year - 10 + i;
if (j + 1 < 10) {
obj.key = obj.year + '/0' + Number(j + 1)
} else {
obj.key = obj.year + '/' + Number(j + 1)
}
this.timeList.push(obj);
}
}
if (this.list.length != 0) {
this.timeList.forEach(item => {
this.list.forEach(v => {
if (v == item.key) {
item.status = true;
}
})
})
}
},
/**
* @param {Object} item 选中后修改状态
*/
changeStatus(item) {
item.status = !item.status;
},
/**
* 打开下拉框
*/
openOptions() {
this.status = !this.status;
this.reset();
this.yearIndex = 0;
this.rightList = this.timeList.slice(0, 12);
},
/**
* 重新赋值选中的状态
*/
reset() {
this.timeList.forEach(v => {
v.status = 0;
})
this.list.forEach(item => {
this.timeList.forEach(v => {
if (item == v.key) {
v.status = 1;
}
})
})
}
}
}
</script>
<style lang="scss" scoped>
.select {
position: relative;
.value-box {
width: 100%;
height: 64rpx;
border: 1rpx solid gainsboro;
line-height: 64rpx;
display: flex;
.item-list {
width: 90%;
display: flex;
overflow: hidden;
.font-active-color {
color: black;
display: flex;
.item-value {
border-radius: 8rpx;
display: flex;
align-items: center;
margin-top: 8rpx;
height: 48rpx;
background-color: pink;
margin-right: 10rpx;
}
}
}
.font-init-color {
color: gray;
}
.item {
margin: 0 10rpx;
}
.icon {
margin-left: auto;
margin-right: 10rpx;
}
}
.box {
position: absolute;
background-color: white;
margin-top: 8rpx;
width: 100%;
border: 1rpx solid gainsboro;
z-index: 99;
.opration {
.cancel {
margin-top: 20rpx;
margin-left: 10rpx;
}
.confirm {
margin-top: 20rpx;
margin-right: 10rpx;
color: deepskyblue;
}
display: flex;
justify-content: space-between;
height: 64rpx;
width: 100%;
}
.data-options {
width: 100%;
display: flex;
height: 400rpx;
.left-content {
text-align: center;
width: 50%;
overflow: scroll;
margin-top: 20rpx;
.active {
color: lightblue;
font-weight: 600;
}
.default {
color: black;
}
.year-box {
margin: 20rpx 0rpx;
}
}
.right-content {
text-align: center;
width: 50%;
overflow: scroll;
margin-top: 20rpx;
.active {
color: lightblue;
font-weight: 600;
}
.default {
color: black;
}
.month-box {
margin: 20rpx 0rpx;
}
}
}
}
}
</style>
总结
当时做的比较早,写js代码的时候好像看出一个逻辑错误,但是我的业务逻辑用居然是没问题的,所以没深究(我很懒的~)。本例主要起到一个抛转引玉的作用,需要适应不同业务的小伙伴可以适实际情况修改。