效果图
组件的使用
- 日程内容可以自定义
- 状态对应颜色可以自定义
<MSchedule :scheduleList="plan" :isExpend="false" :hasNumExpend="3" @handleDetail="handleDetail" @chooseEntireCard="chooseEntireCard"
@changeMonth="changeMonth">
<template v-slot:card="{row}">
<span>时段:{{ row.timePeriod }}</span>
<span>课程:{{ row.course }}</span>
</template>
</MSchedule>
下载组件 使用教程及参数点击这里
npm i mschedule -S
组件完整代码如下
html部分
<template>
<div class="month-container">
<div class="month-top">
<div class="m-btn-wrap">
<span @click="handleShowLastMonth">上一月</span>
<span @click="handleShowToday"> 今天 </span>
<span @click="handleShowNextMonth">下一月</span>
</div>
<span class="m-today-date"> {{ year }}年{{ month > 9 ? month : `0${month}` }}月</span>
<div class="m-card-status">
<div v-for="sta in cardStatus">
<span class="square" :style="{background:sta.color}"></span>
<span class="title">{{ sta.title }}</span>
</div>
</div>
</div>
<div class="m-date-wrap">
<ul class="m-week">
<li>日</li>
<li>一</li>
<li>二</li>
<li>三</li>
<li>四</li>
<li>五</li>
<li>六</li>
</ul>
<ul class="m-day">
<li v-for="(item,index) in days"
:class="{'m-isActive':item.isActive,'m-isCurToday':item.isCurToday}"
:key="index">
<span @click="handleChooseCard(item)" class="m-date" :class="{'m-isCurMonth':item.isNextMonth||item.isLastMonth}">
{{ item.day }}
</span>
<template v-for="(plan,i) in item.planList">
<div :key="`plan${i}`" @click="handleDetail(plan)"
class="m-card-default"
:style="{background: cardStatus[plan.status].color}">
<slot name="card" :row="plan"></slot>
</div>
</template>
</li>
</ul>
</div>
</div>
</template>
js 部分 import MyTools from "../utils/MyTools"; 点击这里
<script>
import MyTools from "../utils/MyTools";
export default {
name: 'monthSchedule',
props: {
list: {
type: Array,
},
cardStatus: {
type: Object,
default: () => {
return {
1: {
title: '已过期',
color: '#9CADADB7'
},
2: {
title: '进行中',
color: '#FF6200'
},
3: {
title: '未开始',
color: '#3291F8'
},
}
}
}
},
data() {
return {
year: '',//年
month: '',//月
days: [],//日期
endTime: null,
startTime: null,
monthValue: '',
}
},
methods: {
changeMonth() {
const date = this.monthValue && this.monthValue.split('-').map(Number) || []
if (date.length === 0) {
return
}
this.year = date[0];
this.month = date[1]
this.days = [];
this.pushDays();
},
//得到当前年这个月分有多少天
getDays(Y, M) {
return new Date(Y, M, 0).getDate();
},
//得到当前年,这个月的一号是周几
getWeek(Y, M) {
let now = new Date()
now.setFullYear(this.year)
now.setMonth(this.month - 1)
now.setDate(1);
return now.getDay();
},
/**
* 获取本月日期
*/
pushDays() {
//将这个月多少天加入数组days
for (let i = 1; i <= this.getDays(this.year, this.month); i++) {
const _day = `${i > 9 ? i : '0' + i}`, _month = `${this.month > 9 ? this.month : '0' + this.month}`,
date = `${this.year}-${_month}-${_day}`;
this.days.push({
day: _day,//
date,
planList: this.list.filter(item => item.date === date),
isCurMonth: true,
month: _month,
year: `${this.year}`,
timestamp: new Date(date).getTime(),//转换时间戳
})
}
this.getLastMonthDays()
this.getNextMonthDays()
},
/**
* 获取下个月的日期
*/
getNextMonthDays() {
const month = this.month < 12 ? this.month + 1 : 1,
year = this.month < 12 ? this.year : this.year + 1,
len = 42 - this.getDays(this.year, this.month) - this.getWeek(this.year, this.month)
//将下个月要显示的天数加入days
for (let i = 1; i <= len; i++) {
const _day = `${i > 9 ? i : '0' + i}`, _month = `${month > 9 ? month : '0' + month}`,
date = `${year}-${_month}-${_day}`;
this.days.push({
day: _day,
date,
month: _month,
year: `${year}`,
planList: this.list.filter(item => item.date === date),
isNextMonth: true,
timestamp: new Date(date).getTime()
})
}
},
/**
* 获取上个月的日期
*/
getLastMonthDays() {
const month = this.month > 1 ? this.month - 1 : this.year > 1970 ? 12 : 1,
year = this.month > 1 ? this.year : this.year > 1970 ? this.year - 1 : 1970,
len = this.getWeek(this.year, this.month),
lastMonthDays = this.getDays(this.year, this.month - 1)
//将上个月要显示的天数加入days
for (let i = 0; i < len; i++) {
const _month = month > 9 ? `${month}` : `0${month}`,
date = `${year}-${_month}-${lastMonthDays - i}`;
this.days.unshift({
day: `${lastMonthDays - i}`,
date,
month: _month,
year: `${year}`,
planList: this.list.filter(item => item.date === date),
isLastMonth: true,
timestamp: new Date(date).getTime(),
})
}
},
/**
* 获取日期数据
*/
getDate() {
let now = new Date();
this.year = now.getFullYear();
this.month = now.getMonth() + 1;
this.pushDays();
},
/**
* 下个月
*/
handleShowNextMonth() {
if (this.month < 12) {
this.month = this.month + 1;
} else {
this.month = this.month = 1;
this.year = this.year + 1;
css部分
<style>
ul {
list-style: none;
}
.month-container {
width: 100%;
border: 1px solid #ddd;
padding: 20px;
box-sizing: border-box;
}
.month-top {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1% 0;
box-sizing: border-box;
}
.month-top .m-btn-wrap {
width: 200px;
display: flex;
justify-content: space-around;
color: #409EFF;
}
.month-top .m-btn-wrap > span {
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
font-size: 15px;
}
.month-top .m-card-status {
display: flex;
width: 20%;
justify-content: flex-end;
}
.month-top .m-card-status > div {
flex: 1;
display: flex;
padding: 0 2%;
white-space: nowrap;
line-height: 20px;
box-sizing: border-box;
}
.month-top .m-card-status > div .square {
display: flex;
width: 16px;
height: 16px;
border-radius: 4px;
box-sizing: border-box;
}
.month-top .m-card-status > div .title {
display: flex;
align-items: center;
line-height: 16px;
margin-left: 4px;
font-size: 14px;
}
.m-date-wrap {
width: 100%;
height: auto;
}
.m-date-wrap .m-week {
width: 100%;
height: 80px;
margin: 0;
line-height: 80px;
display: flex;
flex-direction: row;
font-size: 16px;
background: #EAEDF2;
box-sizing: border-box;
}
.m-date-wrap .m-week > li {
width: 14.28%;
}
.m-date-wrap .m-day {
width: 100%;
display: flex;
flex-direction: row;
padding: 0;
margin: 0;
font-size: 14px;
flex-wrap: wrap;
box-sizing: border-box;
}
.m-day .m-date{
cursor: pointer;
}
.m-date-wrap .m-day > li {
width: 14.28%;
padding: 1%;
min-height: 100px;
box-sizing: border-box;
border: 1px solid #ddd;
}
.m-date-wrap .m-day > li .m-card-default {
cursor: pointer;
width: 100%;
min-height: 60px;
border-radius: 8px;
display: flex;
margin: 6% 0;
flex-direction: column;
justify-content: space-around;
white-space: nowrap;
color: #fff;
background: #FF6200;
padding: 2% 4%;
box-sizing: border-box;
}
.m-date-wrap .m-day > li:nth-child(n+8) {
border-top: none;
}
.m-date-wrap .m-day > li:nth-child(n+1) {
border-right: none;
}
.m-date-wrap .m-day > li:nth-child(7n) {
border-right: 1px solid #ddd
}
.m-isCurMonth {
background: #fff;
color: #c0c4cc;
}
.m-isCurToday {
background: #FFF1F0 10000%;
color: #FF2525;
}
.m-isActive {
background: #409EFF;
color: #f2f8fe;
}
</style>