用vue實現類ant Design的日曆組件

前言

最近在對以前寫的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將數據綁定在每一格子中,實現起來會更簡單。那麼如何做呢

  1. 生成第一行的數據
    第一行和最後一行是比較麻煩的兩行,因爲我們需要和上個月以及下一個月的數據打交道。
    我們首先要獲取幾個值
  • 本月第一天是星期幾
  • 上一個月最後一天是幾號
    舉個例子,本月第一天是星期六,上個月最後一天是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地址
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章