看看需求javascript
組件默認一直呈顯示狀態html
經過某種方式選擇年、月,選擇了年月後,日期列表作相應切換前端
經過單擊某個具體的日期進行日期選擇java
組件初始化時,可配置可選日期的上下限。可選日期和不可選日期須要有樣式上的區別git
提供設定日期的接口,指定具體日期,日曆面板相應日期選中github
日期選擇面板默認隱藏,會顯示一個日期顯示框和一個按鈕,點擊這兩個部分,會浮出日曆面板。再點擊則隱藏。dom
點擊選擇具體日期後,面板隱藏,日期顯示框中顯示選取的日期函數
增長一個接口,用於當用戶選擇日期後的回調處理this
增長一個參數及相應接口方法,來決定這個日曆組件是選擇具體某天日期,仍是選擇一個時間段spa
當設置爲選擇時間段時,須要在日曆面板上點擊兩個日期來完成一次選擇,兩個日期中,較早的爲起始時間,較晚的爲結束時間,選擇的時間段用特殊樣式標示
增長參數及響應接口方法,容許設置時間段選擇的最小或最大跨度,並提供當不知足跨度設置時的默認處理及回調函數接口
在彈出的日期段選擇面板中增長確認和取消按鈕
先完成一個組件的基本結構
(function(window,document){ function Calendar(options){ //傳入配置的中的參數 this.init(); } Calendar.prototype={ init:function(){ this.createDom(); this.loadCss(); this.cacheDom(); this.bindEvents(); this.render(); }, loadCss:function(){ // 把組件所需的樣式表動態加載進來 }, createDom:function(){ // 建立dom對象或者建立html片斷或者建立template }, cacheDom:function(){ // 存儲dom 對象 }, bindEvents:function(){ //事件綁定 }, render:function(){ //渲染函數,更新數據或樣式 } } window.Calendar=Calendar;//把組件對象綁定到全局 }(window,document));
一般我寫組件時的基本結構如上,你能夠根據組件的須要或者本身習慣進行編寫。而後就能夠在html裏面添加如下的代碼就能夠調用咱們的組件了,
<script src='calendar.js></script> <script type='text/javascript'> var a=new Calendar({ // 各類配置 /* 相似於 id:'myCalendar' onSelected:function(){ alert('hello'); } */ }); </script>
下面再看一下咱們的需求,咱們來一 一分析
需求也不是不少嘛,手動斜眼~
先上圖,根據圖再慢慢分析
其實咱們看了需求以後,每一個人都會有一個大概的思路,下面說一下個人思路
首先,要實現一個日期選擇器,最重要的就是要有一個日曆,根據不一樣的年份和月份,日期面板上回顯示每一天和對應的周幾~
其實實現這一點的話就兩點
第一,要根據年份和月份算出每個月有多少天
第二,要計算出每個月的第一天(1號)是周幾
僞代碼以下:
/** * @param {string} year 年份 * @param {string} month 月份 * @param {string} day 號 * @return {object} message * message{ * year 年份 * month 月份 * monthLen 那個月的天數 * whichDay 1號是周幾 * day 號 * } */ function calculate(year,month,day){ var date=year+'/'+month+'/'+'1'; var whichDay=new Date(date).getDay(); var message={ year:year, month:month, monthLen:new Date(year,month,0).getDate(), whichDay:whichDay, day:day }; return message; },
我想看完代碼以後你們應該比較疑惑的是獲取每月天數的那句代碼,這個比較優雅的作法是從這裏看到的,
注意:在Date對象裏month爲0表明的是1月份,month爲5表明6月份,因此我new Date(year,5,0)表明的六月份的第0天,即5月份的最後一天,因此還能夠用getDate()獲取5月份的長度,getDate方法是返回指定日期對象的月份中的第幾天(1-31)。
因此當咱們點擊了月份加減/年份加減的按鈕時,向calculate函數傳入變化後的year,month參數,而後進行渲染,日曆面板改變
其次,」選擇時間段而且另處於開始時間和結束時間之間的日期添加特殊的樣式「這一點也是花了很多時間來寫,
僞代碼以下:
// 初始化 var firstDate,secondDate=[0,0,0]; //點擊日曆面板上的日期的點擊事件的執行函數的片斷,每當點擊事件被觸發,就會執行該片斷 if(self.isSelectRange){ var date=[self.year.innerHTML,self.month.innerHTML,ele.innerHTML]; if(self.firstDate[0]===0){// if(self.secondDate[0]===0){//兩個日期都沒有被設置 self.firstDate=date; }else{//firstDate沒有被設置,secondDate已經被設置, } }else{ if(self.secondDate[0]===0){//firstDate已經設置, self.secondDate=date; if(compareDate(self.firstDate.join('/'),self.secondDate.join('/'))){//若是第一個選擇的日期大於第二次選擇的日期,進行交換 self.firstDate=[self.secondDate,self.secondDate=self.firstDate][0]; } }else{//兩個日期都已經被設置,已經選擇了兩個元素,再次選擇則都 self.secondDate=[0,0,0]; self.firstDate=date; self.clearDayInRangeStyle(); } } self.day.innerHTML=ele.innerHTML; self.render();
firstDate,secondDate分別表明開始時間和結束時間。每次觸發日期的點擊事件時,就會執行以上的代碼片斷,對firstDate和secondDate進行更改,這樣的話,不管是我對日曆面板進行更新或者對開始時間和結束時間之間的日期顯示不一樣的樣式,均可以經過firstDate和secondDate來實現。
顯示不一樣的樣式就判斷日期是否在開始時間和結束時間之間,每次從新render的時候就給選擇過的firstDate和secondDate添加樣式。
包括計算開始時間和結束時間之間的跨度是否在設定的跨度內,咱們點擊按鈕後進行判斷。
最後,看看render函數怎麼實現
關於render函數,有如下幾點須要注意:
清除日曆面板上的全部內容和樣式,樣式經過清除每一個單元格上的類實現
根據每個月1號是周幾和每個月的長度生成每個月的日曆
根據記錄的fisrtDate和secondDate來顯示已經選擇過的選擇的樣式
以上大概是個人思路,我也實現了一個組件,有興趣的朋友能夠點這裏,歡迎找bug~ps:文筆仍是不行,文章寫的好爛。。