因为项目需要用到日历组件,没有找到适用的组件,只能无奈自己写一个了,达到项目使用所需的功能,同时保留了较高的扩展性。
先贴上效果图
screenshots.gif具体day的点击事件逻辑就不贴出来了,有需要的根据自己的项目需求加上click即可
代码分享
-父组件代码
有使用到 elementui 的 el-button el-date-picker,照抄的同学记得下载依赖
<template>
<div>
<div class="top clearfix">
<div class="top-left fl">
<div class="tlt clearfix">
<span class="title1 fl">我的课表</span>
<el-button class="fr ml10" type="primary">下载排课表</el-button>
<div class="block fr">
<el-date-picker
v-model="value"
type="month"
:clearable=false
format="yyyy年 MM月"
@change="changeDate()"
placeholder="查看月份">
</el-date-picker>
</div>
</div>
<Calendar :defaultMonth.sync='defaultMonth'></Calendar>
</div>
</div>
</div>
</template>
<script>
import Calendar from '@/components/Calendar'
export default {
components:{Calendar},
data() {
return {
value:'',
defaultMonth:''
}
},
methods: {
changeDate(){
this.defaultMonth = this.value
}
},
created(){
let time = new Date()
this.value = time
this.defaultMonth = time
}
}
</script>
<style lang="stylus" scoped>
.clearfix::before,
.clearfix::after {
content: '';
display: table;
clear: both;
}
.fl{
float:left;
}
.fr{
float:right;
}
.title1{
color: #333
font-size: 20px;
font-weight 900
}
.top-left
height 750px
width 70%
background-color #fff
padding:20px;
border-radius: 10px;
&>.tlt
line-height 40px;
padding-bottom:10px;
</style>
-子组件代码
<template>
<!-- 日历组件 -->
<div class="calendar-box">
<table class="calendar-table">
<thead>
<th class="fc-day-header">日</th>
<th class="fc-day-header">一</th>
<th class="fc-day-header">二</th>
<th class="fc-day-header">三</th>
<th class="fc-day-header">四</th>
<th class="fc-day-header">五</th>
<th class="fc-day-header">六</th>
</thead>
<tbody>
<tr>
<td
v-for="(item, index) in calendarData"
:key="index"
:style="{'height': height}"
@click="clickDay(item)">
<div class="includeContent"
:class="{
'include': item.include,
'active': defaultDate.indexOf(item.date)>-1
}"
>
<slot name="day" :row="item">
<div class="day">
<span class="d_one">{{ item.day2 }}</span>
<span class="d_two" v-if="defaultDate.indexOf(item.date)>-1">课</span>
<span class="d_three" v-if="defaultDate.indexOf(item.date)>-1" v-text="courseList[defaultDate.indexOf(item.date)]"></span>
</div>
</slot>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'calendarBox',
props: {
type: { // all 可选中显示的所有日期 portion 只能选中当前月份的数据
type: String,
default: 'portion'
},
defaultMonth: { // 默认日期
type: Date,
default () {
let year = new Date().getFullYear() // 当月年份
let month = new Date().getMonth() + 1 // 当月月份
return new Date(year, month - 1, 1)
}
},
height: { //设置td高度
type: String,
default: '94px'
}
},
data () {
return {
calendarData: [],
activeData: null,
defaultDate:['2022-4-1','2022-4-7','2022-4-13','2022-4-18','2022-4-26','2022-4-28','2022-5-5','2022-5-15','2022-5-18','2022-5-20','2022-5-21','2022-5-30'],
courseList:['美术课','武器课','瑜伽课','音乐课','吃饭','睡觉','看电影','逛街','考试','答辩','毕业','结婚'],
// allDate:[ //这里是模拟数据,一般是从后台接口获取而来,需要自己获取的时候拆分成 defaultDate 和 courseList
// {date:'2022-4-1',course:'美术课'},
// {date:'2022-4-7',course:'武器课'},
// {date:'2022-4-13',course:'瑜伽课'},
// {date:'2022-4-18',course:'音乐课'},
// {date:'2022-4-26',course:'吃饭'},
// {date:'2022-4-28',course:'睡觉'},
// {date:'2022-5-5',course:'看电影'},
// {date:'2022-5-13',course:'逛街'},
// {date:'2022-5-14',course:'毕业'},
// {date:'2022-5-20',course:'答辩'},
// {date:'2022-5-25',course:'结婚'},
// ]
}
},
created () {
this.getCalendarDay()
},
methods: {
// 获取日历天数
getCalendarDay () {
let year = new Date(this.defaultMonth).getFullYear() // 当月年份
let month = new Date(this.defaultMonth).getMonth() + 1 // 当月月份
let days = new Date(year, month, 0).getDate() // 当月天数
let prevYear = month === 1 ? (year - 1) : year // 上一年年份
let prevMonth = month === 1 ? 12 : (month - 1) // 上月月份
let prevDays = new Date(prevYear, prevMonth, 0).getDate() // 上一月天数
let lastYear = month === 12 ? (year + 1) : year // 下一年年份
let lastMonth = month === 12 ? 1 : (month + 1) // 下月月份
// let lastDays = new Date(lastYear, lastMonth, 0).getDate() // 下一月天数
let prevMonthArr = [] // 上月数据
let nextMonthArr = [] // 下月数据
let currentMonthArr = [] // 当月数据
// 判断当月1号是星期几
let firstDay = new Date(year, month - 1, 1).getDay()
// 获取显示上月的数据
for (let i = 0; i < firstDay; i++) {
let day = prevDays - firstDay + (i + 1)
let day2 = day >= 10 ? day : ('0' + day)
let month2 = prevMonth >= 10 ? prevMonth : ('0' + prevMonth)
prevMonthArr.push({
year: prevYear,
month: prevMonth,
month2: month2,
day: day,
day2: day2,
date: `${prevYear}-${prevMonth}-${day}`,
date2: `${prevYear}-${month2}-${day2}`,
include: false
})
}
// 获取显示的下一月的数据
for (let i = 0; i < (42 - firstDay - days); i++) {
let day = i + 1
let day2 = day >= 10 ? day : ('0' + day)
let month2 = lastMonth >= 10 ? lastMonth : ('0' + lastMonth)
nextMonthArr.push({
year: lastYear,
month: lastMonth,
month2: month2,
day: day,
day2: day2,
date: `${lastYear}-${lastMonth}-${day}`,
date2: `${lastYear}-${month2}-${day2}`,
include: false
})
}
// 获取当月显示数据
for (let i = 1; i <= days; i++) {
let day2 = i >= 10 ? i : ('0' + i)
let month2 = month >= 10 ? month : ('0' + month)
currentMonthArr.push({
year: year,
month: month,
month2: month2,
day: i,
day2: day2,
date: `${year}-${month}-${i}`,
date2: `${year}-${month2}-${day2}`,
include: true
})
}
this.calendarData = [...prevMonthArr, ...currentMonthArr, ...nextMonthArr]
},
// 设置默认值
setDefaultValue (date) {
if (!date) {
this.activeData = null
return
}
let year = new Date(date).getFullYear() // 当月年份
let month = new Date(date).getMonth() + 1 // 当月月份
let month2 = month >= 10 ? month : ('0' + month)
let day = new Date(date).getDate()
let day2 = day >= 10 ? day : '0' + day
let row = {
year: year,
month: month,
month2: month2,
day: day,
day2: day2,
date: `${year}-${month}-${day}`,
date2: `${year}-${month2}-${day2}`,
include: true
}
this.clickDay(row)
},
clickDay (row) {
if (this.type === 'portion' && !row.include) {
this.$message.closeAll()
this.$message({
type: 'info',
message: '只能选择当前月份的日期'
})
return
}
this.activeData = { ...row }
this.$emit('click', { ...row })
// console.log(this.activeData);
}
},
watch: {
defaultMonth(){
this.setDefaultValue()
this.getCalendarDay()
}
}
}
</script>
<style lang="stylus" scoped>
$blue = #0176F6
.calendar-box {
background-color #f6f6f6
padding 10px;
.calendar-table {
width: 100%;
border-radius: 4px;
display: block;
overflow: hidden;
thead,
tbody {
display: flex;
width: 100%;
}
tr {
width: 100%;
}
th {
height: 50px;
line-height: 50px;
text-align: center;
color: #3E597B;
box-sizing: border-box;
display: inline-block;
width: 14.28%;
}
td {
width: 14.28%;
display: inline-block;
position: relative;
font-size: 16px;
font-weight: 500;
box-sizing: border-box;
text-align: center;
cursor: pointer;
border: solid 2px transparent;
color: rgba(62, 89, 123, 0.3);
background-color: #f5f5f5;
padding: 5px;
&>.includeContent{
border: 1px solid #DDD;
height 80px;
&.include {
color: #3E597B;
background-color: #fff;
}
&.active {
border: 2px solid $blue;
background: #BCDCFF;
color: $blue;
}
&:hover{
border: 2px solid $blue;
}
}
.day {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
&>.d_one{
position: absolute
top 5px
left 5px
}
&>.d_two{
position: absolute
top 5px
right 5px
}
&>.d_three{
width 100%
position: absolute
top 40px
left 50%;
transform: translateX(-50%)
}
}
&:nth-child(1),
&:nth-child(7),
&:nth-child(8),
&:nth-child(14),
&:nth-child(15),
&:nth-child(21),
&:nth-child(22),
&:nth-child(28),
&:nth-child(29),
&:nth-child(35),
&:nth-child(36),
&:nth-child(42) {
background: #f6f6f6; //根据自己需要,设置td周末的背景颜色
}
}
tbody {
.clickDay {
border: solid 2px #00BBBB;
}
}
}
}
</style>
使用注意事项
1.<style lang="stylus" scoped>
这里我用的是stylu
2.子组件props中的 type 和 height 我在父组件中没有传,使用的是子组件的默认值
3.data(){} 中 defaultDate、courseList、allDate参数请根据项目实际获取参数使用
结束 over
网友评论