前言
最近在对以前写的vue项目进行优化,并且进行了一些功能的完善,我写了一个周报系统,其中一个完善的功能就是,可以通过日历选择以往的周报。于是我着手ant Design的一些功能,自己实现了一个周报组件。
一些图片
- 未选择时
- 鼠标移上去
- 选中状态
问题
1. input聚焦问题
我的设想是这样的,日历首先是用v-if="show",show=false
设置了隐藏,我们在点击input框的时候,日历会显示出来,然后我们在点击非日历的部分的时候,日历会隐藏。
<div class="showWeek" @focus ="show=true" @blur="show=false" ref="showWeek" v-if="show">
为了实现这个功能,我给input输入框绑定了focus事件和blur,当focus事件触发时,日历显示,当blur事件触发时,日历隐藏。
可是这时出现了一个问题,我在对日历上的日期进行选择的时候,input框失去了焦距,触发了blur事件。
后面我想了一个办法,就是只给input框绑定click事件,设置一个stop防止冒泡,点击input之后日历显示,
<div class="showWeek" @click.stop ="show=true" ref="showWeek" v-if="show">
然后给document绑定click事件,点击之后日历隐藏。但是document可能会经过很多次的点击,每一次点击都触发日历隐藏显然是不合适的。所以我给show设置了监听,当show的值为false,说明show刚刚隐藏,移除document的点击事件,否则添加。
'show':function(newValue){
if(newValue){
document.addEventListener('click',this.bindEvent);
}else{
document.removeEventListener('click',this.bindEvent);
}
}
2.日历生成问题
在写这个组件的时候,最麻烦的就是,如何生成日历。我首先想的是,用两个v-for的嵌套,外层是今年的第几周,内层是这周的星期几,然后根据年,周,星期几生成天数。但是可能是因为我的算法还有所欠缺,我并没有实现。
咨询了学长,学长和我说,可以先用二维数组,根据年月生成对应的一个月的时间,存在二维数组中,然后用双层v-for将数据绑定在每一格子中,实现起来会更简单。那么如何做呢
- 生成第一行的数据
第一行和最后一行是比较麻烦的两行,因为我们需要和上个月以及下一个月的数据打交道。
我们首先要获取几个值
- 本月第一天是星期几
- 上一个月最后一天是几号
举个例子,本月第一天是星期六,上个月最后一天是31号。如果我们想做一个从周一到周天的日历,那么1号之前就有5天
27 28 29 30 31
计算公式
上个月最后一天的星期数 = 这个月1号的星期数-1
上个月最后一天 - (上个月最后一天的星期数-1)
31 - (6-1-1) = 27
通过这个公式,我们可以求出在6月份的日历中,第一行的开始日期
要特别注意的是,因为周天的getDay方法的返回值为0,而我们要写的是周一到周天的日历,而不是从周日到周六的,所以我们需要对getDay方法进行改写
myGetDay(day){
var w = day.getDay();
if(w === 0){
w = 7;
}
return w;
}
这样,我们就可以根据开始日期,结束日期,生成该周的号数了
numberList(start, end, flag) {
let list = []
for (let i = start; i <= end; i++) {
list.push({
text: i,
flag: !!flag
})
}
return list
}
我们把第一行中上个月的号数存在数组里
let list =
this.numberList(temp, this.lastMonthEndDate, true)
.concat(this.numberList(1, 7 - this.currentMonthFirstDay+1))
this.list.push(list);
把这个月的天数和上个月的天数进行拼接
this.list.push(list);
拼接后存入月份数组中,作为第一行
接下来我们要求本月数据,思路就是, 求出本月的总天数减去第一行的本月天数,取一个余,然后用for循环实现。代码如下。
getDateList() {
this.list = []
// 获取日历第一行的数据(需加上第一个星期中所包含上个月的几天)
//temp计算出上个月最后一天的星期数减去这个月第一天的星期数
//上个月的最后一天是几号
console.log(this.lastMonthEndDate);
//这个月的第一天是星期几
console.log(this.currentMonthFirstDay);
//(this.currentMonthFirstDay - 1)得到的是上个月的最后一天是星期几
//temp的值是在本页呈现的上个月的开始天数
//上个月最后一天是星期五。31号
//31-(5) = 26
//日 一 二 三 四 五
//26 27 28 29 30 31
//let temp = this.lastMonthEndDate - (this.currentMonthFirstDay - 1);
//为了改成星期一到星期五,需要少一天
let temp = this.lastMonthEndDate - (this.currentMonthFirstDay - 1)+1;
// 一 二 三 四 五
// 27 28 29 30 31
// let list =
// this.numberList(temp, this.lastMonthEndDate, true)
// .concat(this.numberList(1, 7 - this.currentMonthFirstDay))
//剩下的时间就得多填一天
let list =
this.numberList(temp, this.lastMonthEndDate, true)
.concat(this.numberList(1, 7 - this.currentMonthFirstDay+1))
this.list.push(list);
//好了,第一行填完了
//剩下的天数,从第一行结束的天数开始算起
temp = (7 - this.currentMonthFirstDay) + 2
/*
* 剩下的行数
*/
// 计算除了第一行剩下的天数
const leftDays = this.currentMonthEndDate - (7 - this.currentMonthFirstDay)-1;
console.log(leftDays);
// 剩下的星期数,决定还要写多少行
const lineNumber = Math.ceil(leftDays / 7)
// 包含下个月日历的天数
const nextDays = 7 - (leftDays % 7)
for (let i = 0; i < lineNumber; i++) {
//最后一行如果包含有别的月的情况
if (i === lineNumber - 1 && nextDays > 0 && nextDays !== 7) {
this.list[lineNumber] =
this.numberList(temp, this.currentMonthEndDate)
.concat(this.numberList(1, nextDays, true))
} else {
this.list.push(this.numberList(temp, temp + 6))
}
temp = temp + 7
}
}
3.点击某一周的一天,选中一整周
这个就是,$event事件,里面有一个path,标志着点击事件的路径,根据点击事件的路径找到点击的行,设置背景色即可。
4.根据选中的周去后台调取数据
因为我是用时间戳来存储时间
然后我又把mysql自己封装了一层(封装的不太好用,我打算用模板字符串优化一下)
let lastSQL = myselfSql.select('content',"*","YEARWEEK(date_format(from_unixtime((weekly_taskData)/1000),'%Y-%m-%d'),1) = "+time+" and user_id="+163+" order by weekly_taskData");
- data_format是吧时间戳转化为‘yyyy-mm-dd’的格式
- YEARWEEK(‘yyyy-mm-dd’,1)返回的值是某年某周
如果逗号后的值是0,算作2018年52周,1算作2019年01周
github地址