帶你輕鬆搞定時間選擇控件原理

前言

  說到這個時間選擇控件,網上有不少各式各樣的,相信不少同窗們也都有用過,因此你們對這個也不陌生。雖然你們都用過這個時間選擇控件,可是卻不多有人去研究其中原理。最近這邊本人利用閒暇時間本身寫了一個時間選擇控件,借這個時間選擇控件向各位同窗們闡述這個時間選擇控件的原理。我向你們演示確定是比較簡單,相對來講更容易理解一點。可是呢,考慮到實用性,我就把這個時間選擇控件改進了一下,讓其變成了一個移動端時間選擇控件,但願同窗們若是喜歡我這邊文章的話,麻煩幫個點個贊哦!不勝感謝!css

項目演示

本文項目地址

https://github.com/ruichengpi...html

本文演示地址

https://ruichengping.github.i...git

本文演示效果圖

圖片描述

--------------------------------分割線----------------------------------github

完整項目地址(移動端)

github地址

https://github.com/ruichengpi...數組

演示地址

https://ruichengping.github.i...瀏覽器

理一下思路

  基於上面的效果演示圖,咱們第一件事就是理清思路。不少同窗呢,一開始若是作這個東西可能一頭霧水,都不知道從哪裏開始入手。這裏我就你們理一下。dom

  對這種插件的開發,我我的建議先不要急着考慮其封裝之類的狀況,咱們就從最簡單的開始入手。那什麼是最簡單的呢?那確定就是html+css+js的模式最簡單的。什麼意思呢?我這裏解釋一下,如今就是單純作一個效果,html控制骨架,css美化樣式,js實現交互,不要考慮複用性。ui

  既然咱們選擇html+css+js先去實現效果,那麼着手開始先把時間選擇控件的html的dom結構寫出來,而後用css去調整其中的樣式。html和css的內容很簡單,這裏我就不把代碼貼出來,同窗們看完這篇文章能夠去個人github項目下中Jcalendarlearn文件夾查看。下面咱們說一下交互有哪些東西。this

JS交互實現

  關於這個JS交互,咱們首先要弄清楚這個時間選擇控件有哪些交互。我先列舉一下:spa

  • 年份、月份的增長減小按鈕

  • 根據input框的位置,設置時間選擇器的位置

  • 根據年份、月份獲取對應的日期數據

  • 日期的選擇

  • 時間選擇器顯示隱藏

下面一一這些功能。

根據年份、月份獲取對應的日期數據

  咱們先來闡述這個功能是如何實現,這是整個時間選擇控件的基石,弄清楚這個,後面的問題都會變得簡單。初看到這個確實很難,一頭霧水,都不知道如何下手。遇到這種問題的時候,先不要考慮如何去實現,首先咱們弄清楚這個日期數據是由那幾塊組成。我認真地想一想,發現每一組日期數據都有這樣一個等式。

日期數據=上一月的日期+這個月的日期+下個月的日期

那爲何會這麼組成呢?可能有同窗們有這樣子的疑問,不急不急,聽我接下來解釋一下。

一個星期是有七天,咱們最長的一個月是31天,就是4個星期餘三天。若是每一行表明星期,那麼五行就能夠搞定了。可是看效果演示圖咱們能夠看出來,咱們用了6行。爲何會多一行?這個問題很好解釋,並非每個月的第一天都是從星期天開始的,因此咱們要考慮最壞的狀況。若是從星期六開始,此時須要6+31=37格(換上一下,就是5行多2格)。爲了知足這種最壞的狀況,咱們就須要6行了。

經過上面解釋,咱們能夠發現有一個特例並不知足這個等式。那就是這個月第一天是從星期天開始的。不過這個特例並不影響咱們用這種思路去思考問題,因此咱們能夠無論這個特例。下面我就看一下,這每一塊數據是如何獲得的。

上個月

關於得出這塊數據,咱們先不要考慮其具體組成。首先考慮的是個數,須要幾個咱們給它弄幾個。怎麼知道須要多少個呢?很簡單,弄清楚這個月的第一天是星期幾就能夠了。

/**
 *獲取currentYear年currentMonth月的第一天是星期幾
 *month參數是要比實際上少一天的
 *0 表明星期天 6表明星期六
 **/
new Date(currentYear,currentMonth-1,1).getDay();

當我得出須要幾個上一月日期數據以後,咱們還須要同樣東西。那就是上一個月的最後一天,根據這個來往前推。

/**
 *獲取currentYear年currentMonth月的最後一天的日期
 *month參數是要比實際上少一天的
 **/
new Date(currentYear,currentMonth-1,0).getDate();

這個月

這個月的日期數據相比較上一個就簡單多了,只須要知道這一月的第一天和最後一天便可。

//獲取currentYear年currentMonth月的第一天的日期
new Date(currentYear,currentMonth-1,1).getDate();
//獲取currentYear年currentMonth月的最後一天的日期
new Date(currentYear,currentMonth,0).getDate();

下一月

這塊數據也很是簡單,總共7*6=42格,剩下幾格就往裏面填幾個。咱們這裏只須要知道下一個月的第一天是多少就好了。

//獲取currentYear年currentMonth月的下一月的一天的日期
new Date(currentYear,currentMonth,1).getDate();

最終的JS代碼

//根據年,月獲取日數組
    function getMonthData(year, month, day) {
        var days = [];
        var today = new Date();
        if (!year | !month | !day) {
            year = today.getFullYear();
            month = today.getMonth() + 1;
            day = today.getDate();
        }
        //獲取該月第一天的Date對象
        var firstDateObj = new Date(year, month - 1, 1);
        //獲取該月第一天對應的星期幾
        var firstDateWeekDay = firstDateObj.getDay();
        //獲取該月最後一天的Date對象
        var lastDateObj = new Date(year, month, 0);
        //獲取該月最後一天的日期
        var lastDate = lastDateObj.getDate();
        //獲取上一個月最後一天的Date對象
        var lastDateOfPrevMonthObj = new Date(year, month - 1, 0);
        //獲取上一個月最後一天的日期
        var lastDateOfPrevMonth = lastDateOfPrevMonthObj.getDate();
        //上月
        for (var i = 0; i < firstDateWeekDay; i++) {
            var className = "available disabled";
            var thisMonth = month - 1;
            var date = lastDateOfPrevMonth - firstDateWeekDay + i + 1;
            if (thisMonth === 0) {
                thisMonth = 1;
            }
            days.push({
                "date": date,
                "showDate": date,
                "thisMonth": thisMonth,
                "className": className
            });
        }
        //本月
        for (var i = 0; i < lastDate; i++) {
            var className = "available";
            var date = i + 1;
            var thisMonth = month;
            if (date === day) {
                className = "available current";
            }
            if (today.getDate() === date && today.getFullYear() === year && today.getMonth() + 1 === month) {
                days.push({
                    "date": date,
                    "showDate": "今天",
                    "thisMonth": thisMonth,
                    "className": className
                });
            } else {
                days.push({
                    "date": date,
                    "showDate": date,
                    "thisMonth": thisMonth,
                    "className": className
                });
            }

        }
        var nextMonthLength = days.length;
        //下月
        for (var i = 0; i < 7 * 6 - nextMonthLength; i++) {
            var className = 'available disabled';
            var date = i + 1;
            var thisMonth = month + 1;
            if (thisMonth === 13) {
                thisMonth = 12;
            }
            days.push({
                "date": date,
                "showDate": date,
                "thisMonth": thisMonth,
                "className": className
            });
        }
        return {
            "year": firstDateObj.getFullYear(),
            "month": firstDateObj.getMonth() + 1,
            "days": days
        }
    }

年份、月份的增長減小按鈕

  這塊沒有難的點,須要注意的就是臨界值得判斷。好比說12月再加1個月,不能變成13月,而是年份加1,月份置爲1.

根據input框的位置,設置時間選擇器的位置

  這塊內容也很簡單,弄清楚left值和top值是如何計算的便可。

top值=input輸入框到瀏覽器窗口頂部的距離+input自身的高度
left值=input輸入框到瀏覽器窗口左邊的距離

  上面須要注意的是距離遊覽器而不是整個文檔,由於咱們用的fixed而不是absolute。

日期的選擇

  這裏沒有難點,可是有一個新手很是容易犯錯的錯誤。在爲日期綁定事件的時候,新手很容易就會找到當前頁面全部日期給它綁定事件。這樣顯然是行不通的,由於日期數據是不斷變得,也就是日期這些dom元素是會替換了的,以前綁定的事件也就不見了,因此我建議你們用事件委託機制。可能會有人反駁我,每一天改變年份和月份的時候在從新綁定一次不就完了,固然這樣也是能夠的。可是不建議,簡單的事情不要複雜化,無故增長開銷。

時間選擇器顯示隱藏

  這個小功能點,很簡單,沒啥可講。須要注意多個實例而且只有一個時間選擇器的dom結構的狀況下,你該如何設計你的顯示隱藏。

結語

  到這裏咱們就把整個時間選擇控件實現整個思路都理了一遍,相信同窗們已經知道如何實現一個時間選擇控件了。快去本身動手作一個本身專屬的時間選擇控件吧!(ps:若是以爲本文寫的不錯,請記得點贊哦!)

相關文章
相關標籤/搜索