由于项目需要,实现一个日历组件,直接上代码,实现逻辑代码里有注释:
<template>
<div class="calendar">
<div class="now-mouth">{{displayDate}}</div>
<div class="calendar-title">
<div class="calendar-select">
<div class="calendar-select-row" v-for="(week,index) in weekName " :key="index">
<input class="checkbox" :ref="'week_'+index" type="checkbox" :name="week" @change="checked('week',index)" />
</div>
<div class="calendar-select-row"></div>
</div>
<div class="calendar-select">
<div class="calendar-select-row" v-for="(week, index) in weekName" :key="index">
<div class="week" > {{week}}</div>
</div>
<div class="calendar-select-row">
<input class="checkbox" ref="checkAll" type="checkbox" @change="checkAll" />
</div>
</div>
</div>
<div class="calendar-body">
<div v-for="(week, weeKIndex) in calendarDay" :key="weeKIndex" >
<div class="calendar-select">
<div
class="calendar-select-row"
v-for="(day, dayIndex) in week" :key="dayIndex"
:class="{isSelected: day.select}"
@click="onClick(day)"
>
<div class="day" v-show="day.day">
{{day.day}}
</div>
</div>
<div class="calendar-select-row">
<input class="checkbox" type="checkbox"
:ref="'row_'+weeKIndex"
v-show="week[0].day || week[6].day"
@change="checked('row',weeKIndex)"
/>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
/**
* Canlendar Module
* ----------------------
* Author:zoboy
* Date: 2019.06.12
*/
import moment from 'moment'
export default {
name: 'Canlendar',
components: {},
data () {
return {
displayDate: '',
nowDay: '',
calendarDay: [],
checkedDay: [],
weekName: ['日', '一', '二', '三', '四', '五', '六']
}
},
props: {
mouth: String
},
mounted () {
this.createCalendar(this.mouth)
},
created () {},
methods: {
onClick (day) {
if (day && day.day) this.$emit('onClick', day)
},
checked (target, index) {
let checkRef = target + '_' + index
let check = this.$refs[checkRef][0].checked
this.calendarDay.forEach(week => {
week.forEach(day => {
if (day && day.day && day[target] === index) day.select = check
})
})
},
checkWork (isOnWork, select) {
this.calendarDay.forEach(week => {
week.forEach(day => {
if (day && day.day) {
if (isOnWork && (day.week > 0 && day.week < 6)) {
day.select = select
} else if (!isOnWork && (day.week === 0 || day.week === 6)) {
day.select = select
}
}
})
})
},
checkAll () {
let check = this.$refs.checkAll.checked
this.calendarDay.forEach(week => {
week.forEach(day => {
if (day && day.day) day.select = check
})
})
},
createCalendar (mouth) {
if (mouth) this.nowDay = moment(mouth).format('YYYY-MM')
else this.nowDay = moment().format('YYYY-MM')
this.displayDate = moment(this.nowDay).format('YYYY年MM月')
this.calendarDay = this.getCurrMonthDays(this.nowDay)
},
getCurrMonthDays (theDay) {
// 获取当前月的第一天
let start = moment(theDay).add('month', 0).format('YYYY-MM') + '-01'
// 获取上一个月的总天数
let lastMonthDays = moment(this.date).subtract(1, 'month').daysInMonth()
// 构造日历的42个格子
let daysArr = [[], [], [], [], [], []]
// 获取当前月的第一天是星期几
let currentWeekday = moment(start).format('E')
// 获取当前月的总天数
let nowMouthDays = moment(theDay).daysInMonth()
for (let i = 0; i < 7; i++) { // 每一周
// 虚拟天数,确定第一行第一列的值(上个月的总天数-当前月第一天的星期几(1)=26就是第一个格子的值,后面的一次类推)
let virtualDay = (lastMonthDays - currentWeekday) + i + 1
for (let j = 0; j < daysArr.length; j++) { // 每一天
daysArr[j][i] = this.getDay(i, j, start, virtualDay + (j * 7), lastMonthDays, nowMouthDays) // 每一行*7
}
}
return daysArr
},
getDay (week, row, start, day, lastMonthDays, nowMouthDays, index) {
let dayObj = {}
if (day <= lastMonthDays) { // 上一月 (*<32)
// return day
dayObj = {'day': ''}
} else if (day <= (lastMonthDays + nowMouthDays)) { // 本月(*<=(31+30))
let dayNum = day - lastMonthDays
let date = moment(start).add(dayNum - 1, 'days').format('YYYY-MM-DD')
dayObj = {
day: dayNum,
date: date,
week: week,
row: row,
isToday: new Date(date).getTime() === new Date(moment().format('YYYY-MM-DD')).getTime(),
select: false
}
} else { // 下一月 (*>(31+30))
// return day - (lastMonthDays + nowMouthDays)
dayObj = {'day': ''}
}
return dayObj
}
},
computed: {},
watch: {
mouth (newMouth) {
this.createCalendar(newMouth)
},
calendarDay: {
handler (canlendar) {
this.checkedDay = []
canlendar.forEach(week => {
week.forEach(day => {
if (day && day.day) {
if (day.select) this.checkedDay.push(day)
// else {
// console.log(day.week, day.row)
// let weekRef = 'week_' + day.week
// let rowRef = 'row_' + day.row
// this.$refs[weekRef][0].checked = false
// this.$refs[rowRef][0].checked = false
// this.$refs.checkAll.checked = false
// }
}
})
})
console.log(this.checkedDay)
},
deep: true
}
}
}
</script>
<style lang="scss" scoped>
$base-light-color: #f2f2f2;
.calendar{
margin: 15px;
width: 248px;
height: 224px;
display: flex;
flex-direction: column;
border-top: 1px solid darken($base-light-color, 5%);
border-left: 1px solid darken($base-light-color, 5%);
.now-mouth{
border-bottom: 1px solid darken($base-light-color, 5%);
border-right: 1px solid darken($base-light-color, 5%);
}
.calendar-title{
.calendar-week{
min-width: 35px;
}
}
.calendar-select{
display: flex;
flex-direction: row;
.calendar-select-row{
min-width: 30px;
min-height: 25px;
border-right: 1px solid darken($base-light-color, 5%);
border-bottom: 1px solid darken($base-light-color, 5%);
// &:last-child {
// border-right: none;
// }
.checkbox{
margin-top: 6px;
margin-left: 7px;
}
.week{
margin-top: 6px;
margin-left: 7px;
}
}
}
.calendar-body{
.day {
margin-top: 4px;
margin-left: 9px;
cursor:pointer;
}
.isSelected {
background-color: #1260ad;
}
}
}
</style>
效果图: