由于是老项目,所以组件是基于vue2.0开发的,没有引入部分ele组件,先看图:
Canledar.vue 代码部分:
<template id="custom-calendar">
<div class="custom-calendar">
<div class="calendar-wrapper">
<div class="calendar-header">
<div class="calendar-current-date">
{{`${currYear}年${currMonth}月`}}
</div>
<div class="calendar-month-control">
<button class="button--default button--mini" type="button" @click="handleMonthChange(-1)">上一月</button>
<button class="button--default button--mini" type="button" @click="handleMonthChange(1)">下一月</button>
</div>
</div>
<div class="calendar-week">
<div class="calendar-week-list">
<div v-for="(item, index) of weekly" :key="index" class="calendar-week-list__item">
{{ item }}
</div>
</div>
</div>
<div class="calendar-date-wrapper">
<div class="calendar-date-list">
<div
:class="{
'calendar-date-list__item': true,
'is-current-month': item.currMonth,
'is-current-day': item.currDay,
'is-actived': item.actived,
'disabled': item.disabled
}"
v-for="(item, index) of dateList"
:key="index"
@click="handleActived(index, item.date)">
<span>{{ item.day }}</span>
<span class="lunar">{{
item.lunar.lunarFestival ?
item.lunar.lunarFestival :
item.lunar.isTerm ?
item.lunar.Term :
item.lunar.IDayCn
}}</span>
<span class="date-status" v-if="showStatusLabel && !item.disabled">
{{statusArr[+!item.disabled].label}}
</span>
</div>
</div>
</div>
<div class="calendar-footer">
<button
type="button"
class="button--default button--small"
v-show="showResetButton"
@click="handleResetCalendar">
重置
</button>
<button
type="button"
class="button--default button--primary button--small"
@click="handleConfirmCalendar"
v-show="showConfirmButton">
确认
</button>
</div>
</div>
</div>
</template>
js部分
// calendarFormatter.js 是网上开源的一个日历转换js
<script type="text/javascript" src="./js/calendarFormatter.js"></script>
<script>
Vue.component('calendar', {
name: 'calendar',
template: '#custom-calendar',
props: {
data: Object, // 已选日期
maxDays: {
type: Number,
default: 7 // 最多可选n天内, -1 表示不限制
},
showResetButton: { // 显示重置按钮
type: Boolean,
default: true
},
showConfirmButton: { // 显示确定按钮
type: Boolean,
default: true
},
showStatusLabel: { // 显示状态文字
type: Boolean,
default: true
}
},
watch: {
"data": {
immediate: false,
handler: function(val, oldVal) {
if (val) {
this.activedDate = { ...val }
}
}
}
},
data() {
return {
weekly: ['日', '一', '二', '三', '四', '五', '六'], // 星期
dateList: [], // 当前日期集合
length: 42, // 日期框长度
currYear: null, // 当前年份
currMonth: null, // 当前月份
currDate: null, // 当天日期
activedDate: {}, // 已选日期
statusArr: [ // 状态
{ label: '不可预定', value: 0 },
{ label: '可预定', value: 1 }
]
}
},
computed: {
getDiffDate() {
if (this.maxDays === null || +this.maxDays === -1) return false
const date = new Date(this.currDate)
date.setDate(date.getDate() + this.maxDays - 1)
date.setHours(0, 0, 0, 0)
return +date
}
},
methods: {
// 初始化日历
initCalendar() {
this.currDate = this.dateFormatter(new Date(), "YYYY-MM-DD")
this.handleMonthChange()
},
// 月份切换
handleMonthChange(diff = 0) {
let date = new Date()
if (diff !== 0) {
date = new Date(`${this.currYear}/${this.currMonth}`)
date.setMonth(date.getMonth() + diff)
}
this.currYear = date.getFullYear()
this.currMonth = date.getMonth() + 1
this.initDateList(this.currYear, this.currMonth - 1)
},
// 根据指定年、月份生成日期数组
initDateList(year, month) {
const firstDate = new Date(year, month, 1) // 当前月第一天
const firstDayWeek = firstDate.getDay() // 当前月第一天为星期几
const lastDate = new Date(year, month + 1, 0) // 当前月最后一天
const lastDayWeek = lastDate.getDay() // 当前月最后一天为星期几
const maxDay = lastDate.getDate() // 当前月最大天数
/*
* 下面分步获取日历的方式也可改为,先算出日历面板上第一个日期的节点,然后在逐步遍历 this.length 次
*/
// 当月日期
let dateList = this.getDateList(firstDate, maxDay, true)
// 补充上月部分日期
firstDate.setDate(-firstDayWeek + 1)
dateList = [
...this.getDateList(firstDate, firstDayWeek),
...dateList
]
// 补充下月部分日期
lastDate.setDate(maxDay + 1)
dateList = [
...dateList,
...this.getDateList(lastDate, this.length - dateList.length)
]
this.dateList = dateList
},
// 获取日期数组
getDateList(date, maxDay, currMonth = false) {
const dateList = []
for (let i = 0; i < maxDay; i++) {
if (i > 0) date.setDate(date.getDate() + 1)
const dateDay = this.dateFormatter(date, "YYYY-MM-DD")
const activatedDay = this.activedDate[dateDay]
dateList.push({
date: dateDay,
day: date.getDate(),
currMonth,
currDay: dateDay === this.currDate ? true : false,
disabled: this.disabledDate(date),
actived: activatedDay?.actived || false,
qty: activatedDay?.qty || 0,
lunar: this.solar2lunar(date)
})
}
return dateList
},
// 日期选中、取消
handleActived(index, val) {
const dateList = this.dateList
if (!dateList[index].disabled) {
if (dateList[index].actived) {
alert('确定取消?')
this.$set(dateList[index], 'actived', false)
delete this.activedDate[val]
} else {
this.$set(dateList[index], 'actived', true)
this.activedDate[val] = dateList[index]
}
}
},
// 禁用日期
disabledDate(time) {
const date = new Date(`${this.currDate}`).setHours(0, 0, 0, 0)
return +time < +date || this.getDiffDate && +time > this.getDiffDate
},
dateFormatter(date, formatter = 'YYYY-MM-DD HH:mm:ss') {
date = (date ? new Date(date) : new Date())
const Y = date.getFullYear() + '',
M = date.getMonth() + 1,
D = date.getDate(),
H = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds()
return formatter.replace(/YYYY|yyyy/g, Y)
.replace(/YY|yy/g, Y.substr(2, 2))
.replace(/MM/g, (M < 10 ? '0' : '') + M)
.replace(/DD/g, (D < 10 ? '0' : '') + D)
.replace(/HH|hh/g, (H < 10 ? '0' : '') + H)
.replace(/mm/g, (m < 10 ? '0' : '') + m)
.replace(/ss/g, (s < 10 ? '0' : '') + s)
},
// 阳历转农历
solar2lunar(date) {
return calendarFormatter.solar2lunar(
date.getFullYear(),
date.getMonth() + 1,
date.getDate()
)
},
// 重置日历
handleResetCalendar() {
this.activedDate = {}
this.handleMonthChange()
},
// 日历点击确定
handleConfirmCalendar() {
this.$emit("update", this.activedDate)
}
},
created() {
this.initCalendar()
}
})
</script>
css 部分
<style>
.custom-calendar {
width: 100%;
height: 800px;
min-height: 200px;
background-color: #fff;
margin-bottom: 16px;
padding: 16px;
box-sizing: border-box;
}
.calendar-wrapper {
width: 100%;
height: 100%;
font-size: 14px;
box-sizing: border-box;
display: flex;
flex-direction: column;
border: 1px solid #eee;
}
.calendar-header, .calendar-week {
width: 100%;
height: 52px;
font-weight: bold;
border-bottom: 1px solid #eee;
box-sizing: border-box;
}
.calendar-header {
display: flex;
justify-content: space-between;
padding: 0 16px;
}
.calendar-week-list,
.calendar-date-list {
display: flex;
flex-wrap: wrap;
height: 100%;
}
.calendar-header > div,
.calendar-week-list > div,
.calendar-date-list > div {
display: flex;
align-items: center;
justify-content: center;
}
.calendar-week-list > div,
.calendar-date-list > div {
height: 100%;
width: 14.2857%;
}
.calendar-date-wrapper {
width: 100%;
flex-grow: 1;
}
.calendar-date-list {
width: 100%;
height: 100%;
box-sizing: border-box;
}
.calendar-date-list .calendar-date-list__item {
height: auto;
color: #a0a0a0;
cursor: pointer;
border-bottom: 1px solid #eee;
border-left: 1px solid #eee;
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
line-height: 1.2;
transition: all .2s cubic-bezier(.645, .045, .355, 1);
}
.calendar-date-list .calendar-date-list__item .date-status {
margin-top: 6px;
font-size: 11px;
}
.calendar-date-list .calendar-date-list__item:not(.disabled) .date-status {
color: #67C23A;
transition: all .2s cubic-bezier(.645, .045, .355, 1);
}
.calendar-date-list .calendar-date-list__item:nth-child(7n + 1) {
border-left-width: 0;
}
.calendar-date-list .calendar-date-list__item .lunar {
font-size: 12px;
}
.calendar-date-list .calendar-date-list__item.is-current-month:not(.disabled) {
color: #000;
}
.calendar-date-list .calendar-date-list__item.is-current-month.is-current-day {
color: rgba(255, 102, 0, 1);
}
.calendar-date-list .calendar-date-list__item.is-current-month.is-current-day:not(.disabled):hover,
.calendar-date-list .calendar-date-list__item.is-current-month.is-current-day.is-actived {
background: rgba(255, 102, 0, 1);
}
.calendar-date-list .calendar-date-list__item.disabled {
background: rgba(238, 238, 238, .3);
}
.calendar-date-list .calendar-date-list__item.is-current-month:not(.disabled):hover,
.calendar-date-list .calendar-date-list__item.is-current-month.is-actived {
background: rgba(255, 102, 0, .8);
color: #fff;
}
.calendar-date-list .calendar-date-list__item:not(.disabled):hover .date-status,
.calendar-date-list .calendar-date-list__item.is-actived .date-status {
color: #fff;
}
.calendar-date-list .calendar-date-list__item:not(.disabled):hover,
.calendar-date-list .calendar-date-list__item.is-actived {
background: rgba(255, 102, 0, .5);
color: #fff;
}
.calendar-date-list .calendar-date-list__item.is-current-month.disabled,
.calendar-date-list .calendar-date-list__item.disabled {
cursor: not-allowed;
}
.calendar-footer {
width: 100%;
height: 58px;
display: flex;
justify-content: flex-end;
align-items: center;
box-sizing: border-box;
padding: 0 16px;
}
button.button--default {
min-width: 60px;
height: 38px;
background: #fff;
border: 1px solid #ccc;
border-radius: 2px;
cursor: pointer;
line-height: 1;
padding: 4px 12px;
transition: all .2s cubic-bezier(.645, .045, .355, 1);
outline: none;
}
button.button--default + button.button--default {
margin-left: 12px;
}
button.button--default.button--small {
height: 34px;
}
button.button--default.button--mini {
height: 30px;
}
button.button--default:hover {
border-color: #3240FF;
color: #3240FF;
}
button.button--default:active {
background-color: #3240FF;
border-color: #3240FF;
color: #fff;
}
button.button--default.button--primary {
background-color: #3240FF;
border-color: #3240FF;
color: #fff;
}
button.button--default.button--primary:hover {
background-color: #5B66FF;
border-color: #5B66FF;
}
button.button--default.button--primary:active {
background-color: #2833CC;
border-color: #2833CC;
}
</style>