您好,登錄后才能下訂單哦!
這篇文章給大家介紹使用JavaScript怎么編寫一個日歷組件,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
想要實現的效果
點擊日期選擇框出現日歷
有個日期控制欄幫助選擇日期, 包括年、月、日的選擇和今天
日歷格子,初次點擊日期選擇框時顯示此刻的日期,日歷格子的日期應該包括這個月的所有天數,同時如果當月的1號不是周日,還應補全從周日到1號的天數。還要在這個月最后1號的后面補全到周六。
日期控制欄和日歷格子的日期還有選擇框里的日期的變化要是同步的。
實現思路
為了組件的可復用性,需要用面向對象的思想。
每個日歷組件都是一個日歷對象,主要包括日期選擇框,日期控制顯示欄,還有日歷格子,為了保持日期控制顯示欄和日歷格子日期同步變化,日期控制欄和日歷里面的每個格子都應該包含一個Date屬性,點擊日歷里的格子,將格子存的Date屬性作為函數參數,調用函數改變日期控制欄顯示的時間。同理,日期控制欄時間變化時,也將Date屬性作為參數調用函數,函數重新繪制日歷格子。
上碼:
function Calendar(parentId) { this.parentElement = document.getElementById(parentId); this.init(); } Calendar.prototype = { init: function() { this.contains = document.createElement("div"); this.contains.onselectstart = function(){return false}; //讓按鈕點擊時不會出現文字被選中的藍色塊 this.dateInput = document.createElement("input"); this.datePicker = document.createElement("div"); this.showDateBar = document.createElement("div"); this.dateBox = document.createElement("div"); this.icon = document.createElement("i"); this.contains.className = 'datepicker-container'; this.dateInput.className = 'date-input'; this.dateInput.readOnly = true; var parent = this; this.dateInput.onclick = function(event){ parent.onDateInputClick(event); //點擊日期選擇框時顯示日歷格子 }; this.contains.onblur = function(){ parent.datePicker.style.display = 'none'; } this.datePicker.className = 'date-picker'; this.datePicker.style.display = 'none'; this.showDateBar.className = 'show-date'; this.dateBox.className = 'date-box'; this.icon.className = 'date-icon'; this.icon.innerHTML = ''; //iconfont這里用的阿里圖標,可以自行替換 this.datePicker.appendChild(this.showDateBar); this.datePicker.appendChild(this.dateBox); this.contains.appendChild(this.dateInput); this.contains.appendChild(this.icon); this.contains.appendChild(this.datePicker); this.parentElement.appendChild(this.contains); }, }
初始化日期控制欄:
drawShowDateBar: function(parentElement){ var parent = this; var nowDate = new Date(); parentElement.date = nowDate; var nowYear = nowDate.getFullYear(); var nowMonth = nowDate.getMonth(); var nowDay = nowDate.getDate(); //showDateBar內容拼接 var contentStr ='<div class="year-input"><span>'+nowYear+'年</span><i class="select-year-btn"></i><ul class="year-select-box" >'; for(var i=0;i<150;i++){ contentStr+='<li>'+(i+1900)+'年</li>'; } contentStr+='</ul></div>' +'<div class="month-input"><i class="prev-month"></i><select class="months-options">' for(var i=0;i<12;i++){ contentStr+='<option>'+(i+1)+'月</option>'; } contentStr+='</select><i class="next-month"></i></div>' +'<div class="day-input"><i class="prev-day"></i><select class="days-options"></select>' +'<i class="next-day"></i></div>' +'<button class="today-btn">今天</button>' +'<div class="days-title">'; var weekday = ['日', '一', '二', '三', '四', '五', '六']; for (var i = 0; i < 7; i++) { contentStr+='<span class="day-title">'+weekday[i]+'</span>'; } contentStr+='</div>'; parentElement.innerHTML = contentStr; this.changeShowDateBar(nowDate); //插入到showTimeBar之后,初始化,傳入的參數是現在的時間 var yearInput = parentElement.firstChild; //年選擇框點擊顯示和隱藏選擇列表 yearInput.onclick = function(){ //target和this的區別 target是觸發事件的元素,this是處理事件的元素 var ul = this.lastChild; ul.style.display==='none'||ul.style.display==='none'? ul.style.display='inline-block':ul.style.display='none'; }; //為年選擇下拉框綁定點擊事件 var yearSelectBox = yearInput.lastChild; var yearLi = yearSelectBox.children; for(var i=0;i<yearLi.length;i++){ yearLi[i].onclick = function(){ parent.showDateBar.date.setFullYear(this.innerText.slice(0,-1)); parent.changeShowDateBar(parent.showDateBar.date); //時間改變之后都要重新調用,因為不同年,不同月,某個月的天數不全一樣 }; } //為month的前后按鈕添加點擊事件 var monthInput = yearInput.nextSibling; monthInput.firstChild.onclick = function(){ var monthOptions = this.nextSibling; if(monthOptions.selectedIndex>0){ parent.showDateBar.date.setMonth(--monthOptions.selectedIndex); }else{ monthOptions.selectedIndex = 11; parent.showDateBar.date.setFullYear(parent.showDateBar.date.getFullYear()-1); parent.showDateBar.date.setMonth(11); } parent.changeShowDateBar(parent.showDateBar.date); }; monthInput.lastChild.onclick = function(){ var monthOptions = this.previousSibling; if(monthOptions.selectedIndex<11){ parent.showDateBar.date.setMonth(++monthOptions.selectedIndex); }else{ monthOptions.selectedIndex = 0; parent.showDateBar.date.setFullYear(parent.showDateBar.date.getFullYear()+1); parent.showDateBar.date.setMonth(0); } parent.changeShowDateBar(parent.showDateBar.date); } monthInput.children[1].onchange = function(){ parent.showDateBar.date.setMonth(this.selectedIndex); parent.changeShowDateBar(parent.showDateBar.date) }; //為day的前后按鈕添加點擊事件 var dayInput = monthInput.nextSibling; dayInput.firstChild.onclick = function(){ var dayOptions = this.nextSibling; if(dayOptions.selectedIndex>0){ parent.showDateBar.date.setDate(dayOptions.selectedIndex--); }else{ parent.showDateBar.date.setMonth(parent.showDateBar.date.getMonth()-1); parent.showDateBar.date.setDate(parent.getDaysOfMonth(parent.showDateBar.date)); } parent.changeShowDateBar(parent.showDateBar.date); }; dayInput.lastChild.onclick = function(){ var dayOptions = this.previousSibling; if(dayOptions.selectedIndex < dayOptions.length-1){ dayOptions.selectedIndex++; parent.showDateBar.date.setDate(dayOptions.selectedIndex+1); }else{ parent.showDateBar.date.setDate(1); parent.showDateBar.date.setMonth(parent.showDateBar.date.getMonth()+1); } parent.changeShowDateBar(parent.showDateBar.date); }; dayInput.children[1].onchange = function(){ parent.showDateBar.date.setDate(this.selectedIndex+1); parent.changeShowDateBar(parent.showDateBar.date) }; //為今天按鈕綁定點擊事件 var todayBtn = dayInput.nextSibling; todayBtn.onclick = function(){ parent.drawPicker(new Date()); parent.changeShowDateBar(new Date()); } },
drawShowDateBar函數為日期控制欄的年份、月份、和天的點擊按鈕設置了點擊事件處理函數。還有選擇下拉框變化的處理函數。
在日期控制欄初始化時,或者改變showDateBar的Date時,都會調用changeShowDateBar 函數。這個函數主要根據傳入的日期改變日期控制欄“日”下拉欄的天數,因為每個月的天數不盡相同,所以要根據傳入的日期來改變。會計算出傳入的日期對應的月份有多少天,使用getDaysOfMonth函數計算。
//計算一個月的天數 getDaysOfMonth: function(primalDate) { var date = new Date(primalDate); //要新建一個對象,因為會改變date var month = date.getMonth(); var time = date.getTime(); //計算思路主要是month+1,相減除一天的毫秒數 var newTime = date.setMonth(month + 1); return Math.ceil((newTime - time) / (24 * 60 * 60 * 1000)); },
changeShowDateBar : function(date){ var yearInput = this.showDateBar.firstChild; var monthInput = yearInput.nextSibling; var dayInput = monthInput.nextSibling; yearInput.firstChild.innerText = date.getFullYear()+'年'; var monthsOptions = monthInput.firstChild.nextSibling; monthsOptions.selectedIndex = date.getMonth(); var daysOptions = dayInput.firstChild.nextSibling; var days = this.getDaysOfMonth(date); var dayStr = ''; for(var i=1;i<=days;i++){ dayStr+='<option>'+i+'日</option>'; } daysOptions.innerHTML = dayStr; // console.log(date.toLocaleDateString()+'changeShowDateBar'); daysOptions.selectedIndex = date.getDate()-1; this.drawPicker(date); },
在日期控制欄的Date變化后,日歷格子的日期也應該要改變,顯示的日期要和日期控制欄的保持一致。所以在changeShowDateBar函數結尾處調用drawPicker函數,重新繪制日歷格子。
繪制日歷格子的思路
drawPicker函數要根據傳入的日期繪制日歷格子。
首先計算傳入的日期月份的天數
計算這個月1號是周幾 。利用Date對象的date.setDate(1) //將天設置為1號 。date.getDay() //得到這天是周幾
如果1號不是周日,則補全周日到1號的天數。可以利用oldDate.setDate(-1) //設置日期為原來日期的上個月的最后一天。注意setDate是會改變當前日期的,并不是返回新的日期。
從1號到這個月最后一天循環。
補全最后一天到周六的天數
drawPicker函數:
drawPicker: function(primalDate) { var date = new Date(primalDate); //要新建一個對象,因為會改變date var nowMonth = date.getMonth()+1; var nowDate = date.getDate(); var spanContainer = []; var dateBox = this.dateBox; dateBox.innerHTML = ''; var time = date.getTime(); var days = this.getDaysOfMonth(date); //計算出這個月的天數 date.setDate(1); //將date的日期設置為1號 var firstDay = date.getDay(); //知道這個月1號是星期幾 for (var i = 0; i < firstDay; i++) { //如果1號不是周日(一周的開頭),則在1號之前要補全 var tempDate = new Date(date); tempDate.setDate(i - firstDay + 1); var span = document.createElement("span"); span.className = "unshow"; spanContainer.push({span : span, date : tempDate}); } for (var i = 1; i <= days; i++) { //1號到這個月最后1天 var span = document.createElement("span"); span.className = 'show'; spanContainer.push({span : span, date : new Date(date)}); date.setDate(i + 1); } for (var i = date.getDay(); i <= 6; i++) { //在這個月最后一天后面補全 var span = document.createElement("span"); span.className = "unshow"; spanContainer.push({span : span, date : new Date(date)}); date.setDate(date.getDate()+1); } for(var i=0;i<spanContainer.length;i++){ var spanBox = spanContainer[i]; var span = spanBox.span; span.year = spanBox.date.getFullYear(); //為每個span元素添加表示時間的屬性 span.month = spanBox.date.getMonth() + 1; span.date = spanBox.date.getDate(); span.innerText = spanBox.date.getDate(); if(span.date === nowDate&&span.month === nowMonth) //如果這個span的日期為與傳入的日期匹配,設置類名為select span.className+=" select"; var parent = this; span.onclick = function(){ //設置點擊事件 var target = event.target; var selected = target.parentElement.getElementsByClassName("select"); for(var i=0 ;i<selected.length;i++){ selected[i].className = selected[i].className.replace(" select",""); }; target.className+=" select"; parent.changeDate(target.year, target.month, target.date); parent.changeShowDateBar(new Date(target.year, target.month-1, target.date)); }; dateBox.appendChild(span); //將span添加到dateBox中 } this.changeDate(primalDate.getFullYear(), primalDate.getMonth()+1, primalDate.getDate()) return; },
//日期框點擊時顯示日歷 onDateInputClick: function(event) { var target = event.target; var value = target.value; var datePicker = this.datePicker; if(datePicker.style.display==='none'){ //這里必須要在js文件里將datePicker.style.display設置為none,如果是在css文件里設置為none,得到的display為"" datePicker.style.display = 'block'; }else{ datePicker.style.display = 'none'; return; } if (!value) this.drawShowDateBar(this.showDateBar); //繪制日歷的顯示欄 }, changeDate : function(year, month, date){ this.dateInput.value = year+"-"+(month<10?("0"+month):month)+"-"+(date<10?("0"+date):date); },
實現效果
有點丑......
實現中遇到的問題
日歷格子的繪制問題 。要補全1號前面到周日的天數,還要補全當月最后1號到周六的天數。日歷格子的繪制可以分為3部分,當月前面、當月和當月后面的。要計算出1號是周幾,然后將這周周日到1號的天數繪制。
當月的日歷從1號到最后1號循環繪制。補全最后1號到周六的天數(date.getDay()<=6)
日歷格子和日期控制欄顯示的同步。在繪制時為每個日歷格子單元保存其代表的Date。點擊格子單元時,調用changeShowDateBar函數,將單元存的Date傳入,改變日期控制欄顯示的日期,然后重繪日歷格子。
每個月天數不同,出現的“日”選擇框天數不同的問題。在changeShowDateBar函數里會根據傳入的Date,計算當月有多少天,然后動態生成“日”選擇框應有的天數。
跨月,跨年的處理。在日期控制欄中,有月份和日的上下按鈕,在處理跨月和跨年時,判斷這月(日)是否為最后一月(日),若為,則日期控制欄的Date的年(月)加1,將顯示的月(日)設為第一月(日),調用changeShowDateBar函數。同理判斷是否為第一月(日)。
用到的Date API
date.getFullYear() //得到date的年份
date.getMonth() //得到月份 0-11
date.getDate() //得到日期 1-31的數字
date.getDay() // 得到這天是周幾 0-6
date.getTime()// 得到date的時間戳 ms表示
date.setFullYear(2017); // 設置年份
date.setMonth(x) // 如果設置為0-11,則date為x年的1-12月,如果比11大,則會往前面推,會跳到x+([(n+1)/12])年的第(n+1)%12個月
如果為負數,例如-1則會調到上一年的最后一月去。
date.setDate(x) // 和setMonth是同理的,它會自動根據當月的天數,判斷是否發生月份的變動。-1代表date跳到上月的最后一天
date.setTime()// 根據時間戳設置date
關于使用JavaScript怎么編寫一個日歷組件就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。