uniapp 自定义级联多选下拉框
此案例需要引入day.js!!!
day.min.js下载 也可自行npm安装后导入
需要作为组件的请自己改下传入props!!!
话不多说,先看功能 ↓
<template>
<view>
<view class="content-box">
<view class="time" @click="openTime" v-if="timeList!=0">{{timeList[0]}} +{{timeList.length}}</view>
<view class="time" @click="openTime" v-else>请选择周度</view>
</view>
<view class="time-box" v-if="timeShow">
<view class="box-head">
<view class="cancel" @click="timeCancel">取消</view>
<view class="confirm" @click="timeConfirm">确认</view>
</view>
<view style="display: flex;overflow-y: scroll;">
<view class="left-box left-box-width">
<view class="yearList-item" v-for="item,index in yearList" :key="item.key" @click="choiceYear(index)">
<text :class="[{'is-selsect':index===tempYearIdx||item.isChecked}]">{{item.value}}</text>
</view>
</view>
<view class="right-box right-box-width">
<view class="week-box">
<view class="week-box-left">
<view class="otherList-item" v-for="item,index in tempMonthList" :key="item.key"
@click="choiceOtherTimeList(item.key,index)">
<text :class="[{'is-selsect':tempOtherTimeIdx===index||item.isChecked}]">{{item.value}}</text>
</view>
</view>
<view class="week-box-right">
<view class="weekList-item" v-for="item,index in tempWeekList" :key="item.key"
@click="choiceWeek(item.key)">
<text :class="[{'is-selsect':item.isChecked}]">{{item.value}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import dayjs from '@/common/day.min.js';
export default {
name: "MultSelect",
data() {
return {
time: '',
timeShow: false,
tempType: '',
tempYearIdx: -1,
tempOtherTimeIdx: -1,
weekCount: '', //记录每月周的数量
timeList: [],//存放数据的数组
yearList: [],
weekList: [],
monthList: [],
tempMonthList: [],
tempWeekList:[],
}
},
onReady() {
this.timeList=[];
this.optionInit();
},
methods: {
//选择周度
choiceWeek(week_key){
if(this.tempOtherTimeIdx==-1){
return ;
}
this.weekList=this.weekList.map(e=>{
if(e.key==week_key){
let newObj={...e,'isChecked':!e.isChecked}
return newObj
}
return e
})
this.tempWeekList=this.tempWeekList.map(e=>{
if(e.key==week_key){
let newObj={...e,'isChecked':!e.isChecked}
return newObj
}
return e
})
let year_key=week_key.split('-')[0];
let month_key=week_key.slice(0,week_key.length-2);
if(this.tempWeekList.some(e=>e.isChecked==true)){
this.tempMonthList=this.tempMonthList.map(e=>{
if(e.key==month_key){
let newObj={...e,'isChecked':true}
return newObj
}
return e
})
this.monthList=this.monthList.map(e=>{
if(e.key==month_key){
let newObj={...e,'isChecked':true}
return newObj
}
return e
})
if(this.tempMonthList.some(e=>e.isChecked==true)){
this.yearList=this.yearList.map(e=>{
if(e.key==year_key){
let newObj={...e,'isChecked':true}
return newObj
}
return e
})
}else{
this.yearList=this.yearList.map(e=>{
if(e.key==year_key){
let newObj={...e,'isChecked':false}
return newObj
}
return e
})
}
}else{
this.tempMonthList=this.tempMonthList.map(e=>{
if(e.key==month_key){
let newObj={...e,'isChecked':false}
return newObj
}
return e
})
this.monthList=this.monthList.map(e=>{
if(e.key==month_key){
let newObj={...e,'isChecked':false}
return newObj
}
return e
})
if(this.tempMonthList.some(e=>e.isChecked==true)){
this.yearList=this.yearList.map(e=>{
if(e.key==year_key){
let newObj={...e,'isChecked':true}
return newObj
}
return e
})
}else{
this.yearList=this.yearList.map(e=>{
if(e.key==year_key){
let newObj={...e,'isChecked':false}
return newObj
}
return e
})
}
}
},
//选择月份并初始化周
choiceOtherTimeList(key,idx) {
if(this.tempYearIdx==-1){
return ;
}
this.tempOtherTimeIdx=idx;
this.initWeekList(key);
},
initWeekList(month_key){
this.tempWeekList=this.weekList.filter(v=>v.key.includes(month_key)&&v.key.length==month_key.length+2);
},
//选择年份并初始化月份
choiceYear(idx) {
this.tempYearIdx=idx;
let year=this.yearList[idx].value;
this.tempOtherTimeIdx=-1;
this.initOtherTimeList(year);
this.initWeekList(year+'-'+1);
},
initOtherTimeList(year) {
this.tempMonthList=this.monthList.filter(v=>v.key.includes(year))
},
//配置项初始化
optionInit(){
let year = new Date().getFullYear();
let month = new Date().getMonth() + 1;
this.time = year + '-' + month;
for (let i = 0; i < 10; i++) {
let yearObj={};
yearObj.key=year - i;
yearObj.value=year - i;
yearObj.isChecked=false;
this.yearList.push(yearObj);
for(let j=0;j<12;j++){
let monthObj={};
monthObj.key=(year-i)+'-'+(j+1)
monthObj.value=j+1
monthObj.isChecked=false;
this.monthList.push(monthObj);
let count=this.getWeekNumOfMonth(year - i,j+1);
for(let k=0;k<count;k++){
let weekObj={};
weekObj.key=(year-i)+'-'+(j+1)+'-'+(k+1);
weekObj.value='第'+(k+1)+'周'
weekObj.isChecked=false;
this.weekList.push(weekObj);
}
}
}
this.tempMonthList=this.monthList.slice(0,12);
this.weekCount = this.getWeekNumOfMonth(year, month);
this.tempWeekList=this.weekList.slice(0,this.weekCount);
},
timeCancel() {
this.timeShow = false;
},
timeConfirm() {
this.timeShow = false;
this.timeList=[]
this.weekList.forEach(e=>{
if(e.isChecked){
this.timeList.push(e.key);
}
})
console.log(this.timeList);
},
getWeekNumOfMonth(year, month) {
// 获取该月的最后一天
const lastDayOfMonth = dayjs(`${year}-${month}`).endOf('month');
// 当月最后一天是周几
let week = lastDayOfMonth.day();
// 当月有多少天
let days = lastDayOfMonth.date();
// 计算出该月有多少周
return Math.ceil((days + 6 - week) / 7);
},
changeType(item, index) {
this.tempTypeIndex = index;
this.tempType = item;
},
cancel() {
this.timeShow = false;
this.typeShow = false;
},
confirm() {
this.typeIndex = this.tempTypeIndex;
this.type = this.tempType;
this.timeShow = false;
this.typeShow = false;
},
openType() {
this.typeShow = !this.typeShow;
},
openTime() {
this.timeShow = !this.timeShow;
}
}
}
</script>
<style lang="scss" scoped>
.week-box {
display: flex;
width: 100%;
height: 100%;
}
.week-box-left,
.week-box-right {
width: 50%;
height: 100%;
overflow-y: scroll;
}
.left-box-width {
width: 33% !important;
}
.right-box-width {
width: 67% !important;
}
.left-box,
.right-box {
width: 50%;
height: 350rpx;
overflow-y: scroll;
text-align: center;
}
.content-box {
display: flex;
.time,
{
font-size: 28rpx;
background-color: #ddd;
border: 1rpx solid gray;
padding: 8rpx 10rpx;
}
.time {
margin-left: 20rpx;
}
}
.yearList-item,
.otherList-item,
.weekList-item {
height: 70rpx;
line-height: 70rpx;
font-size: 28rpx;
}
.is-selsect {
color: deepskyblue;
}
.time-box,
{
.box-head {
position: relative;
top: 0;
display: flex;
height: 60rpx;
font-size: 28rpx;
width: 100%;
justify-content: space-between;
align-items: center;
.cancel,
.confirm {
padding: 8rpx 10rpx;
}
.confirm {
color: deepskyblue;
}
}
height: 400rpx;
width: 100%;
position: fixed;
top:calc(100% - 400rpx);
background-color: #ededed;
}
</style>