效果
index.vue
<!-- 日历 -->
<div class="calendar">
<section class="tab">
<p :class="index==tabOnNum?'on':''" v-for="(item,index) in tabText" :key="index"
@click="tabCurrent(index)">{{ item }}</p>
</section>
<section class="updown">
<div :class="frontdis?'frontdis':'front'" @click="getLastDates"></div>
<p>{{ calendarDate }}</p>
<div :class="dateNum == 0?'nextdis':'next'" @click="getNextDates"></div>
</section>
</div>
<!-- 日历 end -->
export default{
data(){
return{
tabText: ['日', '周', '月'],
tabOnNum: 1, //日:0;周:1;月:2
dateNum: 0,
dateText:'',
frontdis:false,
frontdisDate:'2025-01-01',
startdate: '',
enddate: '',
}
},
mounted(){
},
methods: {
tabCurrent(i) {
this.tabOnNum = i
this.dateNum = 0
this.dateText = this.tabText[i]
let type = (this.tabOnNum).toString()
this.getCurrDateText(type, this.dateNum)
},
// 上一日/上一周/上一月
getLastDates() {
if(this.frontdis){
return
}
const type = (this.tabOnNum).toString()
this.dateNum--
this.getCurrDateText(type, this.dateNum)
},
// 下一日/下一周/下一月
getNextDates() {
if (this.dateNum == 0) {
return
}
const type = (this.tabOnNum).toString()
this.dateNum++
this.getCurrDateText(type, this.dateNum)
},
// 封装一个复用方法
getCurrDateText(type, num = 0) {
switch (type) {
case '0': // 日
const dateRange = this.$util.getDateRange('day', num, true)
this.calendarDate = this.$util.getDateRange('day', num)
;[this.startdate, this.enddate] = dateRange.split('/')
this.getData()
break
case '1': // 周
const weekRange = this.$util.getDateRange('week', num, true)
this.calendarDate = this.$util.getDateRange('week', num)
;[this.startdate, this.enddate] = weekRange.split('/')
this.getData()
break
case '2': // 月
const monthRange = this.$util.getDateRange('month', num, true)
this.calendarDate = this.$util.getDateRange('month', num)
;[this.startdate, this.enddate] = monthRange.split('/')
this.getData()
break
}
},
},
getData(){
// 如果开始日期早于frontdisDate,则使用frontdisDate
if(this.comparisonDate(this.frontdisDate, this.startdate) >= 0) {
this.frontdis=true
}else{
this.frontdis=false
}
//自定义接口获取数据
getDailyXXXXX().then(res=>{
console.log(res)
})
},
comparisonDate(time1,time2){
let date1 = new Date(time1);
let date2 = new Date(time2);
if (date1.getTime() > date2.getTime()) {
console.log("date1 is later than date2");
return 1
} else if (date1.getTime() < date2.getTime()) {
console.log("date1 is earlier than date2");
return -1
} else {
console.log("date1 is the same as date2");
return 0
}
},
}
utils.js
/**
* 格式化日期
* @param {Date} date 日期对象
* @param {Boolean} hasYear 是否包含年份
* @returns {String} 格式化后的日期字符串
*/
formatDate: function(date, hasYear = false) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
return hasYear
? `${year}-${month}-${day}`
: `${month}月${day}日`
},
/**
* 获取日期范围
* @param {String} type 范围类型: day|week|month
* @param {Number} offset 偏移量
* @param {Boolean} hasYear 是否包含年份
* @returns {String} 日期范围字符串
*/
getDateRange: function(type = 'day', offset = 0, hasYear = false) {
const date = new Date()
switch(type) {
case 'day': {
date.setDate(date.getDate() + offset)
const formattedDate = this.formatDate(date, hasYear)
return hasYear ? `${formattedDate}/${formattedDate}` : formattedDate
}
case 'week': {
const curr = date.getDate()
const week = date.getDay() || 7 // 将周日的0改为7
const firstDay = curr - (week - 1) + (offset * 7)
// 创建新的日期对象,避免修改原始日期
const startDate = new Date(date)
startDate.setDate(firstDay)
// 基于开始日期创建结束日期
const endDate = new Date(startDate)
endDate.setDate(startDate.getDate() + 6)
const start = this.formatDate(startDate, hasYear)
const end = this.formatDate(endDate, hasYear)
return hasYear ? `${start}/${end}` : `${start}-${end}`
}
case 'month': {
date.setMonth(date.getMonth() + offset)
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const lastDay = new Date(year, date.getMonth() + 1, 0).getDate()
if(hasYear) {
return `${year}-${month}-01/${year}-${month}-${lastDay}`
}
return `${year}年${month}月`
}
}
},
.calendar {
// padding-top: 160rpx;
margin: 32rpx;
.tab {
padding: 10rpx;
border-radius: 30rpx;
background: #e3e5eb;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
p {
width: 33%;
padding: 9rpx 20rpx;
text-align: center;
color: #979bae;
font-weight: 500;
}
.on {
background: #fff;
border-radius: 20rpx;
color: #18224c;
}
}
.updown {
margin: 48rpx 0;
display: flex;
justify-content: space-between;
align-items: center;
>div{
width: 60rpx;
height: 60rpx;
}
.front{
background: url("../../static/images/message_record/time_btn_front_state_normal.png") no-repeat;
background-size: contain;
}
.front:active{
background: url("../../static/images/message_record/time_btn_front_state_press.png") no-repeat;
background-size: contain;
}
.frontdis{
background: url("../../static/images/message_record/time_btn_front_state_disable.png") no-repeat;
background-size: contain;
}
.next{
background: url("../../static/images/message_record/time_btn_next_state_normal.png") no-repeat;
background-size: contain;
}
.next:active{
background: url("../../static/images/message_record/time_btn_next_state_press.png") no-repeat;
background-size: contain;
}
.nextdis{
background: url("../../static/images/message_record/time_btn_next_state_disable.png") no-repeat;
background-size: contain;
}
image {
width: 60rpx;
height: 60rpx;
}
p {
color: #979bae;
font-family: "PingFang SC";
font-weight: 400;
font-size: 26rpx;
line-height: 36rpx;
}
}
}