34.基于Vue实现的SMCalendar日历组件
2018-11-14 本文已影响1人
圆梦人生
效果:
image.png最近项目种需要用到工作日历,之前写过JQ版本的GitHub,直接把JQ版本换成Vue,SMCalendar样式用到了Less,需要Vue工程安装Less才能使用 (主要用到less命名空间,可改)
代码
index.vue (业务页面)
<!--
@author: SM
@desc: vue日历 demo
-->
<template>
<div>
<button @click="getPrveMonth">上个月</button>
<br>
<button @click="getNextMonth">下个月</button>
<div>
{{currentYear}}年{{(currentMonth)}}月
</div>
<!-- 日历组件 -->
<div class="content">
<x-smcalendar ref="smcalendar" :data="calendarData" @itemClick="itemClick"></x-smcalendar>
</div>
</div>
</template>
<script>
// 导入XSmcalendar日历
import XSmcalendar from './x-smcalendar'
//
export default {
// 组件声明
components: {
// 声明
XSmcalendar
},
// 方法
methods: {
//
initDate(){
// 获取日历组件当前时间
this.currentYear = this.smcalendar.getSMCalendarYear();
this.currentMonth = this.smcalendar.getSMCalendarMonth() + 1;
},
// 日历点击回调
itemClick(data){
console.log('点击日历回传的值:');
console.log(data);
},
// 上个月
getPrveMonth(){
this.smcalendar.getPrveMonth(this.smcalendar.getSMCalendarYear(), this.smcalendar.getSMCalendarMonth());
this.smcalendar.reload();
this.initDate();
},
// 下个月
getNextMonth(){
this.smcalendar.getNextMonth(this.smcalendar.getSMCalendarYear(), this.smcalendar.getSMCalendarMonth());
this.smcalendar.reload();
this.initDate();
}
},
//
mounted(){
//
this.smcalendar = this.$refs.smcalendar;
//
this.initDate();
},
data(){
return {
currentYear: null,
currentMonth: null,
smcalendar: null,
// 模拟数据请求
calendarData: [
{
'ATTEND_TYPE': '1',
'ATTEND_CURR_DATE': '2018-10-18',
'ATTEND_CLOCKIN_CNT': '2',
'WORKING_HOURS': '40'
},
{
'ATTEND_TYPE': '2',
'ATTEND_CURR_DATE': '2018-10-19',
'ATTEND_CLOCKIN_CNT': '1',
'WORKING_HOURS': '60'
},
{
'ATTEND_TYPE': '2',
'isDay': '1',
'ATTEND_CURR_DATE': '2018-10-28',
'ATTEND_CLOCKIN_CNT': '1',
'WORKING_HOURS': '60'
},
{
'ATTEND_TYPE': '0',
'isDay': '0',
'ATTEND_CURR_DATE': '2018-11-28',
'ATTEND_CLOCKIN_CNT': '4',
'WORKING_HOURS': '50'
},
]
}
},
}
</script>
<style>
body {
font-family: "PingFang SC", "\82F9\65B9", "PingFangSC-Regular", "Helvetica Neue", Helvetica, STHeiTi, sans-serif;
-webkit-user-select: none;
user-select: none;
-ms-touch-action: none;
color: #676767;
background-color: #F6F6F6;
font-size: 14px;
}
.content {
background-color: #ffffff;
}
button {
background-color: #387BFC !important;
background-image: -webkit-linear-gradient(223deg, #387BFC 0%, #23B8EE 100%);
background-image: linear-gradient(227deg, #387BFC 0%, #23B8EE 100%);
height: 44px !important;
border-radius: 0 !important;
position: relative;
display: block;
margin-left: auto;
margin-right: auto;
padding-left: 14px;
padding-right: 14px;
box-sizing: border-box;
font-size: 18px;
text-align: center;
text-decoration: none;
color: #FFFFFF;
line-height: 2.33333333;
border-radius: 5px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
overflow: hidden;
width: 100%;
border-width: 0;
outline: 0;
-webkit-appearance: none;
}
</style>
x-smcalendar.vue (组件)
<!--
@author: SM
@desc: vue日历
@verison: 0.1
-->
<template></template>
<script>
export default {
name: "x-smcalendar",
data(){
return {
//日期开始
monthbegday: 1,
//日期变量
monthindex: 1,
//日期工具栏
weekabbrs : [ '日', '一', '二', '三', '四', '五', '六' ],
//一周
todoayArr : [ 7, 6, 5, 4, 3, 2, 1 ],
//当前日期
today : new Date(),
//当前月
monthday : (new Date().getMonth()+1),
//今天
dayDate : (new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + "-" + new Date().getDate())
}
},
//
props: {
//
data: {
default: Array
},
// 考勤类型字段
typeField: {
default: 'ATTEND_TYPE'
},
// 日期字段
dateField: {
default: 'ATTEND_CURR_DATE'
},
// 是否休息日
isDayField: {
default: 'isDay'
}
},
//
methods: {
// 初始化日历组件
newSMCalendar(){
//
this.$el.innerHTML= this.addSMCalendar();
// 事件监听
// 事件绑定
let tdEl = document.querySelectorAll('tbody td[cellday]');
tdEl.forEach((item)=>{
let isClick = item.getAttribute('cellday');
if(isClick){
item.addEventListener('click', (e)=>{
//
let data = this.getData(isClick);
let currenDay = item.getAttribute('data-index');
data.day = currenDay;
// 抛出事件
this.$emit('itemClick', data);
})
}
})
},
// 获取header
getHeader(){
let htmlstr='<thead class="font-size-11 colo-A3A9AF "><tr>';
for(let i=0;i<=6;i++){
htmlstr+='<td align="center" height="10" ';
if(i==0 || i==6)
htmlstr+=' class="color-f45454" '
htmlstr+=">" + this.weekabbrs[i];
htmlstr+='</td>';
}
htmlstr+='</tr></thead>';
return htmlstr;
},
// 获取星期几[0-6]
getSMCalendarDay(){
//
return this.today.getDay();
},
getWeekDay(){
return this.weekabbrs[this.today.getDay()];
},
// 获取年份
getSMCalendarYear(){
//
return this.today.getFullYear();
},
// 获取月份
getSMCalendarMonth(){
//
return this.today.getMonth();
},
//
monthdayweekday(today){
//
let ssdate=new Date(today.getFullYear(), today.getMonth(), this.monthbegday);
//
return ssdate.getDay()
},
//
monthendday(){
let year = this.today.getFullYear();
if (year < 2000) year += 1900; // Y2K fix
let month = this.today.getMonth();
let monarr = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
// check for leap year
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) monarr[1] = "29";
return (monarr[month]);
},
//
validateday(objnum){
let objArr=[];
if(objnum<=this.monthendday(this.today)){
objArr[0]=objnum;
objArr[1]=this.today.getFullYear()+"-"+(this.today.getMonth()+1)+"-"+objnum;
return objArr;
}
return objArr;
},
//
validateCss(defaultDate, dateDay){
//
if(this.compareDay(defaultDate,dateDay)){
return " toDayCalendar";
}
return "";
},
//
compareDay(sdate, edate){
//
if(Date.parse(sdate.replace(/\-/g,"/"))===Date.parse(edate.replace(/\-/g,"/"))){
return true;
}
return false;
},
//
getMarkCalendar(dateDay){
let data = this.data;
// 默认缺勤标识
var maskFalg = '';
//
data.forEach((item)=>{
if(this.compareDay(item[this.dateField], dateDay)){
// 如果日期相等,判断类型
let typeNum = Number(item[this.typeField]);
if(typeNum == 1){
maskFalg = ' dateCqClass '; // 出勤
}else if(typeNum > 1 ){
maskFalg = ' dateClass '; // 缺勤
}
// 判断是否工作日
// 1. isDay为true;2.[0 or 6] 周六日
// 0 休息
if(item[this.isDayField] == '1'){
maskFalg += ' yesDay ';
}else if(item[this.isDayField] == '0'){
maskFalg += ' noDay ';
}
//
return maskFalg;
}
});
//
return maskFalg;
},
// 重新加载
reload(){
//
this.newSMCalendar();
},
// 下个月
getNextMonth(yearStr, monthStr){
//下一年
if(monthStr=="11")
{
yearStr = yearStr+1;
monthStr = -1;
}
this.today = new Date(yearStr,Number(monthStr+1),this. monthbegday);
this.monthdayweekday(this.today);
//当前月
this.monthday = (this.today.getMonth()+1);
this.monthendday(this.today);
},
// 上一月
getPrveMonth(yearStr, monthStr){
//上一年
if(monthStr == "0")
{
yearStr = yearStr-1;
monthStr = 12;
}
this.today = new Date(yearStr,Number(monthStr-1), this.monthbegday);
this.monthdayweekday(this.today);
this.monthday=(this.today.getMonth()+1);//当前月
this.monthendday(this.today);
},
//
getData(dateDay){
//
var data = this.data;
//
var dataArr = {
currentDate: dateDay
};
data.forEach((item)=>{
if(this.compareDay(item[this.dateField], dateDay)){
//
dataArr['record'] = item
}
})
//
return dataArr;
},
// 布局日期组件
addSMCalendar(){
let htmlstr='';
let monthindex=0;
//列头
htmlstr += '<table cellspacing="0" cellpadding="0" width="100%" class="SMCalendar" border="0" cellpadding="0" cellspacing="0" align="center"> ';
htmlstr += this.getHeader();
htmlstr += '<tbody class="font-size-13 ">';
let thatDay = this.monthdayweekday(this.today);
let countDay = Math.ceil((this.monthendday(this.today)-(this.todoayArr[ this.monthdayweekday(this.today) ])) / 7) + 1;
for(let i=1;i<=countDay;i++){
if(monthindex <= this.monthendday(this.today)){//总的天数
htmlstr+='<tr>';
for(let j = 0;j <= 6;j++){
htmlstr+='<td align="center" ';
if(i ==1 ){//首行
if(j >= thatDay){
++monthindex;
let dayStr = this.validateday(monthindex)[0] || '';
let dayId = this.validateday(monthindex)[1] || '';
let dateCss = this.validateCss(this.dayDate,dayId);
let markCalendar = this.getMarkCalendar(dayId);
htmlstr+=' data-index="'+j+'" class="'+dateCss+' '+markCalendar+'" id="'+dayId+'" cellday="'+dayId+'" valign="middle" ><span>'+dayStr+'</span>';
}else{
htmlstr+=' ><span></span>';
}
htmlstr+='</td> ';
}else{//不是首行
++monthindex;
let dayStr = this.validateday(monthindex)[0] || '';
let dayId = this.validateday(monthindex)[1] || '';
let dateCss = this.validateCss(this.dayDate,dayId);
let markCalendar = this.getMarkCalendar(dayId);
htmlstr+=' data-index="'+j+'" id="'+dayId+'" cellday="'+dayId+'" class="'+dateCss+' '+markCalendar+'" valign="middle"><span>'+dayStr+'</span></td>';
}//end if
}//end for
htmlstr+='</tr>';
}//end if
}//end for
htmlstr+='</tbody>';
htmlstr+='</table>';
//end 日历
return htmlstr;
}
},
mounted(){
// 渲染日历
this.newSMCalendar();
},
//
beforeDestroy(){
// 事件移除
let tdEl = document.querySelectorAll('tbody td[cellday]')
tdEl.forEach((item)=>{
let isClick = item.getAttribute('cellday')
if(isClick){
item.removeEventListener('click')
}
})
}
}
</script>
<style lang="less">
/*
SMCalendar 日历样式
*/
.SMCalendar {
margin: 0;
padding: 0;
.color-f45454 {
color: #f45454;
}
.colo-A3A9AF {
color: #A3A9AF;
}
.font-size-11 {
font-size: 11px;
}
tbody td {
height: 46px;
}
tbody td span {
display: block;
width: 40px;
height: 40px;
line-height: 40px;
border-radius: 20px;
color: #0D0E10;
position: relative;
}
/*
周六日
*/
tbody td[data-index = '0'] span,
tbody td[data-index = '6'] span,
tbody td.noDay span {
color: #F45454 !important;
}
/*
工作日
*/
tbody td.yesDay span {
color: #0D0E10 !important;
}
.toDayCalendar span {
background: #B8D8FF;
}
.dateClass span:after,
.dateCqClass span:after {
content: '';
position: absolute;
bottom: 3px;
width: 5px;
height: 5px;
left: 16px;
border-radius: 5px;
background: #F45454;
}
.dateCqClass span:after {
background: #388CF3;
}
}
</style>