前言
最近在對以前寫的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地址