<template>
<div class="calendar" v-show="boxShow" :class="boxShow ? 'start' : 'close'">
<div class="flex fl-j-b head">
<div class="prev">
<i @click="iconClick(-2)" class="prevPlus el-icon-d-arrow-left c-pointer"></i>
<i @click="iconClick(-1)" class="prevs el-icon-arrow-left c-pointer"></i>
</div>
<div class="title">{{year}}年{{month}}月</div>
<div class="next">
<i @click="iconClick(1)" class="next el-icon-arrow-right c-pointer"></i>
<i @click="iconClick(2)" class="nextPlus el-icon-d-arrow-right c-pointer"></i>
</div>
</div>
<div class="week">
<div>日</div>
<div>一</div>
<div>二</div>
<div>三</div>
<div>四</div>
<div>五</div>
<div>六</div>
</div>
<div class="day">
<span
@click="handleChange(item)"
v-for="(item,index) in calendarList"
:key="index"
class="transition"
:class="[
item.prev || item.next ? 'prev':'',
item.now ? 'now' : '',
item.select ? 'select' : ''
]"
>
{{ item.day }}
</span>
</div>
</div>
</template>
<script>
export default{
props:{
value:{type:Boolean},
dateList:{type:Array,default:[]}
},
computed:{
boxShow:{
get(){
return this.value;
}
}
},
data(){
return {
calendarList:[],
year: new Date().getFullYear(),
month:new Date().getMonth() + 1
}
},
created(){
this.createCalendar()
},
methods:{
handleChange(item){
if(!item.month)return;
item.id = Number(item.date.replace(/\//g,''));
this.$emit('emitDate',item);
},
iconClick(num){
const nums = this.month + num;
if (nums > 12) {
this.year += 1;
this.month = 1;
} else if (nums < 1) {
this.year -= 1;
this.month = 12;
} else {
this.month = nums;
}
this.createCalendar();
},
createCalendar() {
const calendarList = [];
const now = new Date();
const year = this.year;
const month = this.month;
const daysInMonth = new Date(year, month, 0).getDate();
const firstDayOfWeek = new Date(year, month - 1, 1).getDay();
let date = 1;
let prevMonthDays = new Date(year, month - 1, 0).getDate();
for(let i = 0; i < 6; i++){
for(let j = 0; j < 7; j++){
if(i == 0 && j < firstDayOfWeek){
calendarList.push({
day:prevMonthDays - (firstDayOfWeek - j - 1),
month:false,
prev: true,
select: false
});
}else if(date > daysInMonth){
calendarList.push({
day:date - daysInMonth,
month:false,
select:false,
next:true,
})
date++;
}else{
const isNowDay = date === now.getDate() && month === now.getMonth() + 1 && year === now.getFullYear();
calendarList.push({
day:date,
now:isNowDay,
month:true,
select:false,
date:`${year}/${month}/${date}`,
showDate:`${month}.${date}`
});
date++;
}
}
}
this.calendarList = this.pdSelect(calendarList);
},
pdSelect(calendarList){
const props = JSON.parse(JSON.stringify(this.dateList));
return calendarList.map(dateItem => {
const isSelect = props.length > 0 && props.some(item => item.date === dateItem.date);
dateItem.select = isSelect;
return dateItem;
})
},
},
watch:{
dateList(){
this.pdSelect(this.calendarList);
}
}
}
</script>
<style lang="scss">
.start{
animation: starts 0.5s cubic-bezier(0.075, 0.82, 0.165, 1) forwards;
transform-origin: top left;
}
.close{
animation: closes 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
transform-origin: top left;
}
@keyframes starts {
from{
scale: 0;
}
to{
scale: 1;
}
}
@keyframes closes {
from{
transform: translateX(0);
}
to{
transform: translateX(-10%);
}
}
.calendar{
position: absolute;
width: 240px;
padding: 8px;
box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.2);
border-radius: 3px;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
.week{
margin-top: 8px;
color: rgba(0,17,34,0.8);
display: grid;
grid:auto-flow /repeat(7, 34.28px);
text-align: center;
padding-bottom: 8px;
border-bottom: 1px solid #D9DCDE;
}
.day{
display: grid;
grid: auto-flow / repeat(7, 34.28px);
color: rgba(0,17,34,0.8);
text-align: center;
>span{
margin: 4px;
height: 26.28px;
line-height: 26.28px;
background-color: #fff;
border-radius: 3px;
cursor: pointer;
user-select: none;
}
>span:hover{
background: #FFECDB;
}
.select{
background-color: #FF963A !important;
color: #fff !important;
}
.prev{
color: rgba(0,17,34,0.4) !important;
}
.now{
color: #FF963A;
}
}
}
</style>
手写自定义日历选择器
于 2023-06-28 13:13:02 首次发布