先上效果图
一、整个数据总计为42个格子,格式为六行七列,单个天数数据格式datas单个字段
day: 1 //当前是几号
isMonth: "" //是否是当前月份(空值是当前月,prev上个月,current下个月,判断class)
isToday: false //是否是今天,对今天要进行颜色高亮
isWork: false //当前是否是工作日
isXiu: false //当前是否休息
time: "2021-11-1" //当前日期全称
timeStamp: 1635696000000//当前日期时间戳
ps:当前代码中只标识了上个月为班、下个月为休(上方图可以体现),可自行获取节假日信息并修改日历数据,需获取以当前月为中心的上下月共计三个月数据,修改isWork与isXiu字段(英语菜0.0)
html
<div class="time-section">
<div class="sec-search">
<div class="sea-left">
</div>
<div class="sea-right">
</div>
</div>
<div class="calendar-cont">
<div class="calendar-header">
<div class="ehader-left">
<span>{{this.year}}年{{this.month}}月</span>
</div>
<div class="ehader-right">
<div class="select-month">
<div class="prew-month" @click="prevMonth">
<el-button style="border:0" >上个月</el-button>
</div>
<div class="today" @click="selToday">
<el-button style="border:0" >今天</el-button>
</div>
<div class="current-month" @click="nextMonth">
<el-button style="border:0" >下个月</el-button>
</div>
</div>
</div>
</div>
<div class="calendar-body">
<div class="calendar-table">
<table>
<thead>
<th>一</th>
<th>二</th>
<th>三</th>
<th>四</th>
<th>五</th>
<th>六</th>
<th>天</th>
</thead>
<tbody>
<tr v-for="(val,inx) in datas" :key="inx">
<td
v-for="(item,index) in val"
:key="index"
:class='[item.isMonth,{"is-today":item.isToday},{"is-selected":selectTimeStep == item.timeStamp}]'
@click="clickDay(item)"
@contextmenu.prevent="contextMenuDay(item,$event)">
<div>
<span>{{item.day}}</span>
<span
v-if="item.isXiu || item.isWork"
:class='[{"xiu":item.isXiu},{"work":item.isWork}]'
>{{item.isXiu ? '休' : '班'}}</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="dialog-set" ref='dialogSet' v-show="showDom">
<ul>
<li>
<span>设置为休息日</span>
</li>
<li>
<span>设置为工作日</span>
</li>
<li>
<span>取消所有设置</span>
</li>
<li @click="showDom = false">
<span>取消</span>
</li>
</ul>
</div>
js
export default {
data() {
return{
year: null, //当前正在查阅年份(翻到2022年那就是2022)
month: null, //当前正在查阅月份
day: null, //当前正在查阅天
today:null, //今日日期
datas:[], //数据格式
isToday:[], //今天日期 拆分为数组
selectTimeStep:null,//选中日期时间戳
showDom:false //右击显示弹窗内容
}
},
created(){
const date = new Date();
this.isToday[0] = this.year = date.getFullYear();
this.isToday[1] = this.month = date.getMonth() + 1;
this.isToday[2] = this.day = date.getDate();
this.today = `${this.year}-${this.month}-${this.day}`;
this.selectTimeStep = new Date(`${this.isToday[0]}/${this.isToday[1]}/${this.isToday[2]}`).getTime();
this.initDate()
},
mounted(){
document.onclick = ()=>{
this.showDom = false
}
},
methods:{
//初始化日历数据
initDate(){
let lastMonth = [];
let calendarMonth = [];
let isWeek = new Date(this.year,this.month -1 , 1).getDay() ==0 ? 6 :new Date(this.year,this.month -1 , 1).getDay()-1 //当月开始是周几
let isMonthDay = new Date(this.year,this.month-2,0).getDate(); //当月多少天
let isPrevMonthDay = new Date(this.year,this.month-1,0).getDate(); //上个月是多少天
for(let i=1; i<isMonthDay+1; i++){
calendarMonth.push({
day:i,
timeStamp:new Date(`${this.year}/${this.month}/${i}`).getTime(),
isWork:false,
isXiu:false,
isMonth:'',
isToday:this.isToday[0] == this.year && this.isToday[1] == this.month && this.isToday[2] == i,
time:`${this.year}-${this.month}-${i}`,
})
}
for(let k=isPrevMonthDay-isWeek; k<isPrevMonthDay; k++){
lastMonth.push({
day:k,
timeStamp:new Date(`${this.month == 12 ? this.year-1 : this.year}/${this.month-1}/${k}`).getTime(),
isWork:true,
isXiu:false,
isMonth:'prev',
isToday:false,
time:`${this.month == 12 ? this.year-1 : this.year}-${this.month-1}-${k}`,
})
}
for(let y=1; y<43-(isMonthDay + isWeek);y++){
calendarMonth.push({
day:y,
timeStamp:new Date(`${this.month == 12 ? this.year+1 : this.year}/${this.month+1}/${y}`).getTime(),
isWork:false,
isXiu:true,
isMonth:'current',
isToday:false,
time:`${this.month == 12 ? this.year+1 : this.year}-${this.month+1}-${y}`
})
}
calendarMonth = [...lastMonth,...calendarMonth]
this.datas = this.spArr(calendarMonth,7);
},
//格式化数据
spArr(arr, num){
if(num < 1){
return newArr
}
let newArr = [];
for(let i =0;i<arr.length;){
newArr.push(arr.slice(i,i+=num));
}
return newArr;
},
//上个月
prevMonth(){
if(this.month < 2){
this.month = 12;
this.year -= 1
}else{
this.month -= 1
}
this.initDate()
},
//下个月
nextMonth(){
if(this.month > 11){
this.month = 1;
this.year += 1
}else{
this.month += 1
}
this.initDate()
},
//回到今天
selToday(){
this.year = this.isToday[0]
this.month = this.isToday[1]
this.day = this.isToday[2]
this.initDate()
},
//点击某一天
clickDay(item){
if(item.isMonth == 'prev'){
this.prevMonth()
}else if(item.isMonth == 'current'){
this.nextMonth()
}
this.selectTimeStep = item.timeStamp
},
//右击某一天
contextMenuDay(item,event){
this.selectTimeStep = item.timeStamp
this.showDom = true
this.$refs.dialogSet.style.left = event.x + 'px';
this.$refs.dialogSet.style.top = event.y + 'px';
},
}
}
css
<style type="text/scss" lang="scss">
.time-section{
padding: 10px;
.sec-search{
display: flex;
}
.sea-left{
flex: 1;
display: flex;
}
.sea-right{
display: flex;
}
.calendar-cont{
border: 1px solid rgb(235, 238, 245);
padding: 5px 10px;
margin-top: 10px;
.calendar-header{
display: flex;
padding-bottom: 5px;
.ehader-left{
flex: 1;
display: flex;
align-items: center;
span{
color: #000;
}
}
.ehader-right{
.select-month{
display: flex;
> div{
border: 1px solid rgb(235, 238, 245);
cursor: pointer;
}
:nth-child(2){
border-left: 0;
border-right: 0;
}
}
}
}
.calendar-body{
border: 1px solid rgb(235, 238, 245);
.calendar-table{
table{
width: 100%;
th{
padding: 10px 0;
color: rgb(96, 98, 102);
}
tr{
.is-selected{
background-color: rgb(242, 248, 254);
color: rgb(64, 158, 255);;
}
.is-today{
color: rgb(64, 158, 255);;
}
.prev{
color: rgb(192, 196, 204);
}
.current{
color: rgb(192, 196, 204);
}
td{
vertical-align: top;
border-top: 1px solid rgb(235, 238, 245);
border-right: 1px solid rgb(235, 238, 245);
transition: background-color 0.2s ease 0s;
div{
height: 85px;
padding: 8px;
display: flex;
span:first-child{
flex: 1;
}
.xiu{
color: #198FFF;
}
.work{
color:red;
}
}
&:hover{
cursor: pointer;
background-color: rgb(242, 248, 254);
}
}
}
}
}
}
}
}
.dialog-set{
position: fixed;
left: 50%;
top: 50%;
ul{
border-radius: 8px;
border: 1px solid rgb(228, 231, 237);
overflow: hidden;
li{
padding: 10px 15px;
cursor: pointer;
background: #fff;
&:hover{
background: rgb(245, 247, 250);
}
span{
color: rgb(96, 98, 102);
}
}
}
}
</style>
时间紧迫没优化代码,后期会更新一波