在做h5移动端app时,因业务需要,要做按日区间选择开始和结束日期,按月区间选择开始和结束月份,ui组件中有按日区间选择的,没有按月区间选择,所以结合业务自己写了一个。
<template>
<van-action-sheet
v-model="showDate"
position="bottom"
@close="closeCalendar"
title="选择月份"
round
:style="{ height: '80%' }"
ref="monthDate"
>
<ul class="content">
<li v-for="(item, index) in years" :key="index" v-scroll>
<div class="monthTitle">{{ item.year }}年</div>
<van-row>
<van-col
span="6"
v-for="(childItem, key) in item.children"
:key="key"
:class="childItem.monthClass"
>
<div
class="monthList"
@click="selectList(item, childItem)"
:class="childItem.isSelect === true ? 'isSelect' : ''"
>
<div :class="childItem.disabledMonth == true ? 'isDisabled' : ''">
{{ childItem.month }}月
</div>
<div
class="startEnd"
:class="
childItem.text == '开始' || childItem.text == '结束'
? 'fontSize'
: ''
"
>
{{ childItem.text }}
</div>
</div>
</van-col>
</van-row>
</li>
</ul>
<div class="footBtn" default="footer">
<div class="footBox">
<van-button @click="onReset" type="primary">重 置</van-button>
<van-button @click="onConfirm" type="primary">确 定</van-button>
</div>
</div>
</van-action-sheet>
</template>
<script>
import { Toast } from "vant";
export default {
props: {
isAllowSameDay: {
type: Boolean,
},
calendarshow: {
type: Boolean,
},
yearLength: {
type: Number,
},
defaultDate: {
type: Array,
required: true,
},
},
data () {
return {
years: [],
monthList: [
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九",
"十",
"十一",
"十二",
],
showDate: this.calendarshow,
selectArr: [],
currentYear: new Date().getFullYear(), //当前年份
currentMonth: new Date().getMonth() + 1, //当前月份
startDefaultYear: new Date().getFullYear(), //开始年份
startDefaultMonth: new Date().getMonth() + 1, //开始月份
endDefaultYear: new Date().getFullYear(), //结束年份
endDefaultMonth: new Date().getMonth() + 1, //结束月份
startText: "开始",
endText: "结束",
startEndText: "开始/结束"
};
},
directives: {
// 自定义指令 月历定位到当前年份
scroll: {
inserted (el) {
el.scrollIntoView();
},
},
},
watch: {
calendarshow (val) {
this.showDate = val; //显示隐藏月历
},
defaultDate (val) {
this.startDefaultYear = val[0].getFullYear(); //开始年份
this.startDefaultMonth = val[0].getMonth() + 1; //开始月份
this.endDefaultYear = val[1].getFullYear(); //结束年份
this.endDefaultMonth = val[1].getMonth() + 1; //结束月份
this.setDefaultMonth();
},
},
created () {
this.initCalendar()
},
methods: {
// 初始化月历
initCalendar () {
const that = this;
for (let i = 1; i <= that.yearLength; i++) {
const item = {
year: that.currentYear - (that.yearLength - i),
children: [],
};
for (let j = 0; j < that.monthList.length; j++) {
let list = {
month: that.monthList[j],
isSelect: false,
value: j + 1,
text: "",
};
// 判断当前月之后的月份不可选
if ((item.year == that.currentYear && j + 1 > that.currentMonth) || (item.year == that.currentYear - (that.yearLength - 1) && j + 1 < that.currentMonth)) {
list.disabledMonth = true;
} else {
list.disabledMonth = false;
}
item.children.push(list);
}
that.years.push(item);
}
},
// 设置默认值
setDefaultMonth () {
const that = this;
const startYear = that.startDefaultYear; //默认开始年份
const endYear = that.endDefaultYear; //默认结束年份
const startMonth = that.startDefaultMonth; //默认开始的年份
const endMonth = that.endDefaultMonth; //默认开始的年份
that.selectArr = [];
that.years.map((item) => {
item.children.map((list) => {
list.text = "";
list.isSelect = false;
// 当前起始年份、月份都相同
if (startYear == endYear && startMonth == endMonth) {
list.monthClass = "";
if (item.year == startYear && list.value == startMonth) {
list.text = that.startEndText;
list.isSelect = true;
that.monthSaveArr(startYear, startMonth, list.text);
}
} else {
// 起始年份相同、月份不同
if (item.year == startYear && list.value == startMonth) {
list.text = that.startText;
list.isSelect = true;
that.monthSaveArr(item.year, list.value, list.text);
}
if (item.year == endYear && list.value == endMonth) {
list.text = that.endText;
list.isSelect = true;
that.monthSaveArr(item.year, list.value, list.text);
}
}
});
});
},
// 选择的月份存入一个数组中
monthSaveArr (year, month, text) {
const dataItem = {
year: year,
month: month,
text: text
};
this.selectArr.push(dataItem);
},
// 选择月份
selectList (item, childItem) {
const that = this;
const selectStartYear = that.selectArr[0].year; //选择开始的年份
const selectStartMonth = that.selectArr[0].month;//选择开始的月份
// 大于当前月份不可选
if (childItem.disabledMonth == true) {
return;
}
// 开始月份 (如果数组为空 或者 已经选了开始结束月份为同一月) 选择开始月份
if (that.selectArr.length == 0 || that.selectArr[0].text == that.startEndText) {
that.cancelSelectMonth();
childItem.text = that.startText;
that.monthSaveArr(item.year, childItem.value, childItem.text);
} else if (that.selectArr.length == 1) {
if (item.year == selectStartYear && childItem.value == selectStartMonth) {
// 开始、结束月份是否可选同一天
if (that.isAllowSameDay == true) {
childItem.isSelect = true;
childItem.text = that.startEndText;
that.monthSaveArr(item.year, childItem.value, childItem.text);
return;
} else {
childItem.isSelect = true;
childItem.text = that.startText;
return;
}
}
// 选择的月份不能超过12个月
if ((item.year > this.selectArr[0].year && childItem.value >= this.selectArr[0].month) || (item.year - this.selectArr[0].year > 1)) {
Toast("结束月份不能超过12个月");
return;
}
if ((item.year == selectStartYear && childItem.value < selectStartMonth) || item.year < selectStartYear) {
that.cancelSelectMonth();
childItem.text = that.startText;
that.monthSaveArr(item.year, childItem.value, childItem.text);
} else {
// 结束月份
childItem.text = that.endText;
that.monthSaveArr(item.year, childItem.value, childItem.text);
that.setAreaBackground();
}
} else if (that.selectArr.length == 2) {
that.cancelSelectMonth();
childItem.text = that.startText;
that.monthSaveArr(item.year, childItem.value, childItem.text);
}
childItem.isSelect = !childItem.isSelect;
},
// 取消已选中的月份
cancelSelectMonth () {
this.selectArr = [];
this.years.map((item) => {
item.children.map((ev) => {
ev.text = "";
ev.isSelect = false;
ev.monthClass = "";
});
});
},
// 添加开始、结束区间的背景颜色
setAreaBackground () {
const startYear = this.selectArr[0].year; //开始年份
const endYear = this.selectArr[1].year; //结束年份
const startMonth = this.selectArr[0].month; //开始年份
const endMonth = this.selectArr[1].month; //结束年份
this.years.map((item) => {
// 起始年份相同
if (item.year == startYear && item.year == endYear) {
item.children.map((ev) => {
if (endMonth - startMonth >= 1) {
if (ev.value == startMonth) {
ev.monthClass = "calendarStartColor";
} else if (ev.value == endMonth) {
ev.monthClass = "calendarEndColor";
} else if (ev.value > startMonth && ev.value < endMonth) {
ev.monthClass = "calendarMiddleColor";
}
}
})
} else if (endYear > startYear) {
// 开始年份小于结束年份
if (item.year == startYear) {
// 起始月份
item.children.map((ev) => {
if (ev.value == startMonth) {
ev.monthClass = "calendarStartColor";
} else if (ev.value > startMonth) {
ev.monthClass = "calendarMiddleColor";
}
})
} else if (item.year == endYear) {
// 结束月份
item.children.map((ev) => {
if (ev.value == endMonth) {
ev.monthClass = "calendarEndColor";
} else if (ev.value < endMonth) {
ev.monthClass = "calendarMiddleColor";
}
})
} else if (item.year > startYear && item.year < endYear) {
// 开始月份与结束月份区间的加背景色
item.children.map((ev) => {
ev.monthClass = "calendarMiddleColor";
})
}
}
});
},
// 确认
onConfirm () {
this.$emit("confirmMonth", this.selectArr);
},
// 重置日期
onReset () {
this.$emit("resetCalendar");
},
// 关闭
closeCalendar () {
this.$emit("closeCalendar");
}
}
};
</script>
<style lang="stylus" scoped>
/deep/.van-action-sheet__close {
right: auto;
left: 0px;
}
/deep/.van-action-sheet__header{
font-size: 1rem;
font-family: PingFang SC;
font-weight: bold;
color: #333333;
}
.content {
font-family: PingFang SC;
padding-bottom: 84px;
/deep/.van-row {
padding: 1.11rem 0 0 0;
}
/deep/.van-col--6 {
margin-bottom: 1.11rem;
position: relative;
}
.calendarStartColor{
background-image: linear-gradient(to right, #fff , #e6f5fc);
}
.calendarEndColor{
background-image: linear-gradient(to left,#fff , #e6f5fc);
}
.calendarMiddleColor {
background-color: #e6f5fc;
}
.monthTitle {
background: #E5E5E5;
font-size: 0.83rem;
font-weight: bold;
color: #333333;
padding: 0.61rem 0;
}
.monthList {
width: 3rem;
height: 2.22rem;
display: flex;
flex-flow: column;
color: #333333;
justify-items: center;
align-items: center;
border-radius: 0.56rem;
margin: 0 auto;
padding: 0 0.22rem 0.22rem 0.22rem;
div:first-child {
height: 0.81rem;
line-height: 0.81rem;
padding: 0.44rem 0 0.22rem 0;
font-size: 0.89rem;
font-weight: 500;
}
.startEnd {
height: 0.61rem;
line-height: 0.61rem;
font-size: 0.53rem;
font-weight: 500;
color: #FFFEFE;
}
.fontSize {
font-size: 0.61rem;
}
div {
display: flex;
flex-flow: row;
}
}
.isDisabled {
color: #ccc;
}
.isSelect {
background: #0097E0;
color: #fff;
}
}
.footBtn {
position: fixed;
bottom: 0;
width: 100%;
padding: 0.66rem 0 1.53rem 0;
display: flex;
background: #fff;
.footBox {
padding: 0 16px;
display: flex;
flex-flow: row;
width: 100%;
}
.van-button {
border-radius: 2rem;
height: 2.5rem;
line-height: 2.5rem;
flex: 1;
margin: 0 1rem;
font-size: 1rem;
}
.van-button:nth-child(1) {
width: 80%;
color: #000;
font-size: 14px;
background: white;
border: 2px solid #666 !important;
border-radius: 40px;
margin: 0 1rem;
}
.van-button:nth-child(2) {
width: 80%;
color: #fff;
font-size: 14px;
background: white;
border-radius: 40px;
margin: 0 1rem;
border: none;
background: -webkit-gradient(linear, right top, left top, from(#0068b7), to(#0097e0));
background: linear-gradient(-90deg, #0068b7, #0097e0);
}
}
</style>
组件引用
<month-filter :defaultDate="monthDate.monthDefaultDate" :calendarshow="monthDate.monthCalendarShow" :isAllowSameDay="monthDate.isAllowSameDay" :yearLength="monthDate.yearLength" @closeCalendar="monthDate.monthCalendarShow = false" @confirmMonth="selectMonth" @resetCalendar="resetMonthCalendar">
</month-filter>
monthDate:{
monthCalendarShow:false,
yearLength:10,
monthDefaultDate:[
new Date(), new Date() //设置区间
],
isAllowSameDay:true // 可选同一个月份
},
// 选择月份区间
selectMonth(data) {
if(data.length ==2 ){
// 这里是获取的开始和结束的值
}else if(data.length==1){
if(data[0].text !="开始/结束"){
Toast("请选择正确的月份区间");
return;
}else{
// 这里是开始和结束的月份相同
}
}
this.monthDate.monthCalendarShow = false;
},
resetMonthCalendar(){ //重置月份}
按月区间选择组件还可优化,欢迎大家给出意见,谢谢!
效果图如下:
开始月份到结束月份
开始结束月份可选当月: