說到這個時間選擇控件,網上有不少各式各樣的,相信不少同窗們也都有用過,因此你們對這個也不陌生。雖然你們都用過這個時間選擇控件,可是卻不多有人去研究其中原理。最近這邊本人利用閒暇時間本身寫了一個時間選擇控件,借這個時間選擇控件向各位同窗們闡述這個時間選擇控件的原理。我向你們演示確定是比較簡單,相對來講更容易理解一點。可是呢,考慮到實用性,我就把這個時間選擇控件改進了一下,讓其變成了一個移動端時間選擇控件,但願同窗們若是喜歡我這邊文章的話,麻煩幫個點個贊哦!不勝感謝!css
https://github.com/ruichengpi...html
https://ruichengping.github.i...git
--------------------------------分割線----------------------------------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項目下中Jcalendar下learn文件夾查看。下面咱們說一下交互有哪些東西。this
關於這個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();
//根據年,月獲取日數組 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.
這塊內容也很簡單,弄清楚left值和top值是如何計算的便可。
top值=input輸入框到瀏覽器窗口頂部的距離+input自身的高度
left值=input輸入框到瀏覽器窗口左邊的距離
上面須要注意的是距離遊覽器而不是整個文檔,由於咱們用的fixed而不是absolute。
這裏沒有難點,可是有一個新手很是容易犯錯的錯誤。在爲日期綁定事件的時候,新手很容易就會找到當前頁面全部日期給它綁定事件。這樣顯然是行不通的,由於日期數據是不斷變得,也就是日期這些dom元素是會替換了的,以前綁定的事件也就不見了,因此我建議你們用事件委託機制。可能會有人反駁我,每一天改變年份和月份的時候在從新綁定一次不就完了,固然這樣也是能夠的。可是不建議,簡單的事情不要複雜化,無故增長開銷。
這個小功能點,很簡單,沒啥可講。須要注意多個實例而且只有一個時間選擇器的dom結構的狀況下,你該如何設計你的顯示隱藏。
到這裏咱們就把整個時間選擇控件實現整個思路都理了一遍,相信同窗們已經知道如何實現一個時間選擇控件了。快去本身動手作一個本身專屬的時間選擇控件吧!(ps:若是以爲本文寫的不錯,請記得點贊哦!)