vue2日历组件
【效果图】
<template>
<div style="width: 100%">
<!-- <div> -->
<!-- <div>{{ startDate.getMonth() + 1 + '-' + startDate.getDate() }}</div>
<div>{{ endDate.getMonth() + 1 + '-' + endDate.getDate() }}</div> -->
<!-- <button @click="generateDates">生成日期</button> -->
<div class="lableBoxClass flexBetween">
<div class="lableClass">请假日期</div>
<div>{{ selectedDatesStr }}</div>
</div>
<div class="calenderBoxClass">
<!-- <div>选中的日期:{{ selectedDatesStr }}</div> -->
<div class="date-scale">
<span v-for="(day, index) in scaleDays" :key="index">{{ day }}</span>
</div>
<ul class="date-list">
<li v-for="(date, index) in showDates" :key="index">
<div @click="toggleDateSelection(date)" class="date-item" :class="{ grayColor: isDateDisabled(date), selected: isSelected(date) }">{{ date }}</div>
</li>
</ul>
</div>
</div>
</template>
<script>
import { Toast } from 'vant'
export default {
name: 'CalendarVue',
props: {
startDate: {
type: Date,
default() {
return new Date()
}
},
endDate: {
type: Date,
default() {
return new Date()
}
}
},
data() {
return {
// startDate: new Date('2024-12-19'),
// endDate: new Date('2025-01-05'),
showDates: [], // 用于存储页面显示的日期数组
selectableDates: [], // 用于存储可选的日期数组
scaleDays: ['一', '二', '三', '四', '五', '六', '日'], // 用于存储日期刻度的数组
selectedDates: {}, // 用于存储选中的日期,键为日期,值为是否选中
selectedDatesArr: [] // 用于存储选中的日期数组
}
},
computed: {
selectedDatesStr() {
if (this.selectedDatesArr.length > 0) {
return this.selectedDatesArr.join(',')
}
return '请点击需要请假的日期'
}
},
created() {
// 生成日期
this.generateDates()
this.getSelectableDates()
},
mounted() {},
methods: {
isDateDisabled(date) {
return !this.selectableDates.includes(date)
},
generateDates() {
if (!this.startDate || !this.endDate) {
alert('请选择开始日期和结束日期')
return
}
// 重置日期数组和刻度数组
this.showDates = []
const startDate = new Date(this.startDate)
const endDate = new Date(this.endDate)
console.log(90, this.formatDate(startDate), this.formatDate(endDate))
// 找到第一个星期一
let currentDate = new Date(startDate)
while (currentDate.getDay() !== 1) {
// getDay() 返回的是 0(星期日) 到 6(星期六)
currentDate.setDate(currentDate.getDate() + 1)
}
// 重新设置currentDate为区间开始日期
currentDate = new Date(startDate)
this.showDates = [...this.getDatesFromThisMonday(this.startDate)]
console.log(100, this.showDates)
// 生成日期数组
while (currentDate <= endDate) {
this.showDates.push(this.formatDate(currentDate))
currentDate.setDate(currentDate.getDate() + 1)
}
console.log(107, this.showDates)
let nextSundayArr = this.getDatesFromEndDateToNextSunday(this.endDate)
if (nextSundayArr.length > 0) {
nextSundayArr.forEach(item => {
this.showDates.push(item)
})
}
console.log(115, this.showDates)
},
// formatDate(date)<-->将日期对象转换为 "月份.日期" 格式
formatDate(date) {
const month = date.getMonth() + 1 // 月份从0开始,所以需要+1
const day = date.getDate()
return `${month}.${day}`
},
getSelectableDates() {
let startShowDate = new Date(this.startDate)
let endShowDate = new Date(this.endDate)
console.log(131, startShowDate, endShowDate)
while (startShowDate < endShowDate) {
let formattedDate = startShowDate.getMonth() + 1 + '.' + startShowDate.getDate()
this.selectableDates.push(formattedDate) // 将格式化后的日期添加到数组中
startShowDate.setDate(startShowDate.getDate() + 1) // 移动到下一天
}
console.log(138000, this.selectableDates)
// return this.selectableDates
},
//getDatesFromThisMonday(startDate)<-->获取从当前周一到起始日期【startDate】的日期数组,并转换为 "月份.日期" 格式(与参数【showDates】(页面展示的日期)相关)
getDatesFromThisMonday(startDate) {
// 创建一个当前日期的副本,以避免修改原始日期对象
let today = new Date(startDate.getTime())
// 找到这周一的日期
let thisMonday = new Date(today.getTime())
thisMonday.setDate(today.getDate() - today.getDay() + (today.getDay() === 0 ? -6 : 1)) // 设置为周一
// 生成从这周一到今天的日期数组,并转换为 "月份.日期" 格式
let dates = []
let current = new Date(thisMonday.getTime()) // 从这周一开始
while (current < today) {
// 包含今天
// 转换日期格式为 "月份.日期"
let formattedDate = current.getMonth() + 1 + '.' + current.getDate()
dates.push(formattedDate) // 将格式化后的日期添加到数组中
current.setDate(current.getDate() + 1) // 移动到下一天
}
// console.log(136, dates)
return dates // 返回日期数组
},
//getDatesFromEndDateToNextSunday(endDate)<-->获取从结束日期【endDate】到下一个周日之间的所有日期数组,并转换为 "月份.日期" 格式(与参数【showDates】(页面展示的日期)相关)
getDatesFromEndDateToNextSunday(endDate) {
let current = new Date(endDate.getTime())
// 如果endDate是周日,则将日期设置为下一天(周一)
if (current.getDay() == 0) {
return []
}
current.setDate(current.getDate() + 1)
let dates = []
// 循环直到当前日期是下一个周日
while (current.getDay() !== 0) {
// 格式化日期为 "月份.日期"
let formattedDate = current.getMonth() + 1 + '.' + current.getDate()
// 将格式化后的日期字符串添加到数组中
dates.push(formattedDate)
// 将日期加1天
current.setDate(current.getDate() + 1)
}
// 如果endDate不是周日,我们才添加当前周日
if (endDate.getDay() !== 0) {
let formattedSunday = current.getMonth() + 1 + '.' + current.getDate()
dates.push(formattedSunday)
}
console.log(165, dates)
// 返回包含所有格式化日期的数组
return dates
},
toggleDateSelection(date) {
// 切换日期的选中状态
if (this.isDateDisabled(date)) {
Toast('不可选择范围外的日期')
return
}
// 切换选中状态
const isSelected = this.isSelected(date)
this.$set(this.selectedDates, date, !isSelected)
// 根据新的选中状态更新数组
if (!isSelected) {
// 如果之前未选中,现在选中了,则添加到数组中
this.selectedDatesArr.push(date)
} else {
// 如果之前已选中,现在取消了,则从数组中移除
const index = this.selectedDatesArr.indexOf(date)
if (index !== -1) {
this.selectedDatesArr.splice(index, 1)
}
}
},
isSelected(date) {
// 检查日期是否被选中
return this.selectedDates[date] === true
}
}
}
</script>
<style lang="scss" scoped>
.lableBoxClass {
padding: 15px;
font-size: 15px;
display: flex;
.lableClass {
width: 100px;
color: #1f2022;
flex-shrink: 0;
&::after {
content: '*'; /* 使用Unicode字符表示红星 */
color: red;
margin-left: 5px;
}
}
}
.calenderBoxClass {
// padding-left: 15px;
// padding-right: 10px;
// background-color: yellow;
}
</style>
<style scoped>
.date-scale {
display: flex;
flex-direction: row;
justify-content: space-around;
flex: 0 0 calc(100% / 7 - 10px); /* 假设你想要每个日期项之间有10px的间隙 */
margin: 5px; /* 这将创建10px的间隙(每个方向5px) */
text-align: center;
margin-bottom: 10px;
}
.date-scale span {
display: inline-block;
width: 30px; /* 根据需要调整刻度宽度 */
text-align: center;
}
.date-scale {
display: flex;
justify-content: space-between;
}
.date-list {
display: flex;
flex-wrap: wrap;
list-style: none;
padding: 0;
}
.date-list li {
flex: 0 0 calc(100% / 7 - 10px); /* 假设你想要每个日期项之间有10px的间隙 */
/*width: calc(100vw / 7- 10px); */
text-align: center;
font-style: 16px;
}
.date-item {
/*margin: 5px;*/
background-color: #e6eefc;
width: calc(100vw / 7);
margin-bottom: 8px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.date-list:nth-child(3) {
border-radius: 10px;
}
.grayColor {
color: gray;
background-color: white;
}
.selected {
background-color: rgb(19, 96, 231); /* 选中的日期背景色为蓝色 */
color: white; /* 选中的日期字体颜色为白色 */
border-radius: 5px;
}
</style>
调用组件
<CalendarVue :startDate="startDate" :endDate="endDate" />