Part 6-1 JavaScript – 月曆上下月顯示
填滿月曆表格目前是寫在js/updateData.js中的updataData函式,在該函式中,我們取得今年今月今日的資訊填入calendar物件中,然後再根據calendar物件的日期相關資料填滿月曆表格,接著,我們要滑鼠點選月曆月份左右二個箭頭按鈕,更新月曆表格,為些,我們要把填月曆表格的程式片段包裝成一個函式fillInMonth(),以便於我們呼叫這個函式來顯示今月、上月(上上月…)、下月(下下月…)的月曆表格,以下的程式,大家可以看到,把updateData函式一分為二:updateDate與fillInMonth二個函式:
function updateData(){ let today = new Date(); calendarData.currentDate.year = today.getFullYear(); calendarData.currentDate.month = today.getMonth() + 1; calendarData.currentDate.day = today.getDay(); calendarData.currentDate.date =today.getDate(); calendarData.calendar.month = calendarData.currentDate.month; calendarData.calendar.year = today.getFullYear(); document.getElementById("cur-year").innerHTML = calendarData.currentDate.year; document.getElementById("cur-day").innerHTML = getWeekDayName( calendarData.currentDate.day ); document.getElementById("cur-month").innerHTML = getMonthName ( calendarData.currentDate.month ); document.getElementById("cur-date").innerHTML = addOrdinalIndicator ( calendarData.currentDate.date ); fillInMonth(); } function fillInMonth(){ document.getElementById("cal-year").innerHTML = calendarData.calendar.year; document.getElementById("cal-month").innerHTML = getMonthName ( calendarData.calendar.month ); var monthDays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 32]; //第一個元素放個啞巴元素,好讓我們可以用1~12來存取月份的天數 //判斷今年是否是閏年 if ( ((calendarData.calendar.year % 4 == 0) && (calendarData.calendar.year % 100 != 0)) || (calendarData.calendar.year % 400 == 0) ) monthDays[2] = 29; var weekDay = (new Date(calendarData.calendar.year, calendarData.calendar.month,1)).getDay() ; //取得今年今月1日為禮拜幾 console.log(weekDay); var days = document.getElementsByTagName("td"); //中間段,當月 for (var i = 1; i <= monthDays[calendarData.calendar.month]; i++){ days[weekDay + i - 1].innerHTML = i; } //上個月段 for (var i = (weekDay-1), day = monthDays[calendarData.calendar.month-1]; i >=0; i--, day--){ days[i].innerHTML = day; days[i].classList.add("color"); } //下個月段 for (var i = (weekDay+monthDays[calendarData.calendar.month]), day = 1; i <days.length; i++, day++){ days[i].innerHTML = day; days[i].classList.add("color");`` } //處理今日元素表格的顯著背景設定 if (document.getElementById("current-day")) { document.getElementById("current-day").removeAttribute("id"); } days[weekDay + calendarData.currentDate.date - 1].setAttribute("id", "current-day"); }
先寫下previousMonth與nextMonth二個函式:
function previousMonth(){ console.log("Prev..."); } function nextMonth(){ console.log("Next..."); }
函式只輸出prev或Next,用來測試動作是否有反應。
接著,在二個箭頭按鈕的標籤加上onClick事件處理,指定當滑鼠在其上按了左鍵或右鍵對應的事件處理函式。
<tr> <th colspan="7" class="border-color"> <h4 id="cal-year">2019</h4> <div > <i class="fas fa-caret-left icon" onclick="previousMonth()"></i> <h3 id="cal-month">January</h3> <i class="fas fa-caret-right icon" onclick="nextMonth()"></i> </div> </th> </tr>
存檔,測試,按F12,打開console,按左右二個箭頭按鍵,檢查console是否有列印出prev和next…
二個事件處理函式皆加上fillInMonth函式的呼叫:
function previousMonth(){ console.log("Prev..."); calendarData.calendar.month--; fillInMonth(); } function nextMonth(){ console.log("Next..."); calendarData.calendar.month++; fillInMonth(); }
存檔測試,有幾個問題浮出來了:
1.月曆表格元素的顏色顯示不正常,當月的日期元素是白色,操作幾次之後,會發現,當月的日期元素混到顏色了…,這個問題很容易解決,我們在填表之前,先把有設定color屬性的元素去除掉color屬性設定:
for (var i = 0; i <= 41; i++){ if (days[i].classList.contains("color")) days[i].classList.remove("color"); }
2.進行月份加加減減時,會超出月份的值域,也就是會小於等於0,大於12,此時,我們要加上判斷,
當值等於0時,月份設為12,然後年份減1,當值大於12時,月份設為1,然後年份加1。
程式如下:
function previousMonth(){ console.log("Prev..."); calendarData.calendar.month--; if (calendarData.calendar.month == 0) { calendarData.calendar.month = 12; calendarData.calendar.year--; } fillInMonth(); } function nextMonth(){ console.log("Next..."); calendarData.calendar.month++; if (calendarData.calendar.month >12) { calendarData.calendar.month = 1; calendarData.calendar.year++; } fillInMonth(); }
註:date大約可從1970年往前往後285,616年,這個App應該沒人一直按左鍵2000下,使得年變負的,如果真有人要一直按一直按…,如何不要讓year變成負的?
用滑鼠按左右箭頭雖然方便,但效率不好(箭頭會隨著月份名稱長度位置會有改變,眼睛要盯著箭頭,滑鼠要跟上…),另一個方式就是按滑鼠的左右鍵!我們可以透過補捉鍵盤事件,利用鍵盤的左右鍵來觸發previousMonth與nextMonth二個函式。
取得 JavaScript KeyCode
document.onkeydown = function(e) { switch (e.keyCode) { case 37: previousMonth(); break; case 39: nextMonth(); break; } };
另外,我們在填日期時,會將今日的表格元素進行顯著設定,但是隨著上下月的更新月曆,也都會對今日(但不是今月)元素表格進行顯著設定,此時,我們加上一個判斷式,只要左右二邊的月份不一樣,我們就不做顯著設定,程式碼如下:
if (calendarData.currentDate.year == calendarData.calendar.year && calendarData.currentDate.month == calendarData.calendar.month) { days[weekDay + calendarData.currentDate.date - 1].setAttribute("id", "current-day"); }
等等,還有一個問題,當今月是1月的時候,若用今月的值減1取到的上個月值會是0,在我們的月份日數陣列裏頭,第0個元素是啞巴元素,一月的上個月應該是12,我們必須再處理這個狀況。
preMonth = calendarData.calendar.month-1; if (preMonth == 0) preMonth = 12; for (let i = (weekDay-1), day = monthDays[preMonth]; i >=0; i--, day--){ days[i].innerHTML = day; days[i].classList.add("color"); }
var calendarData = { currentDate : { day : "", date : "", month : "", year : "", }, calendar:{ month : "", year : "" } }; function getWeekDayName(day){ var weekDayNames = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]; return weekDayNames[day]; } function getMonthName(month){ var monthNames = ["","January","February","March","April","May","June","July","August","September","October","November","December"]; return monthNames[month]; } function addOrdinalIndicator(date){ switch(date){ case 1: case 21: case 31: return date + "<sup>st</sup>"; case 2: case 22: return date + "<sup>nd</sup>"; case 3: case 23: return date + "<sup>rd</sup>"; default: return date + "<sup>th</sup>"; } } function updateData(){ let today = new Date(); calendarData.currentDate.year = today.getFullYear(); calendarData.currentDate.month = today.getMonth() + 1; calendarData.currentDate.day = today.getDay(); calendarData.currentDate.date =today.getDate(); calendarData.calendar.month = calendarData.currentDate.month; calendarData.calendar.year = today.getFullYear(); document.getElementById("cur-year").innerHTML = calendarData.currentDate.year; document.getElementById("cur-day").innerHTML = getWeekDayName( calendarData.currentDate.day ); document.getElementById("cur-month").innerHTML = getMonthName ( calendarData.currentDate.month ); document.getElementById("cur-date").innerHTML = addOrdinalIndicator ( calendarData.currentDate.date ); fillInMonth(); } function fillInMonth(){ var monthDays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; //第一個元素放個啞巴元素,好讓我們可以用1~12來存取月份的天數 document.getElementById("cal-year").innerHTML = calendarData.calendar.year; document.getElementById("cal-month").innerHTML = getMonthName ( calendarData.calendar.month ); //判斷今年是否是閏 if ( ((calendarData.calendar.year% 4 == 0) && (calendarData.calendar.year % 100 != 0)) || (calendarData.calendar.year % 400 == 0) ) monthDays[2] = 29; let weekDay = (new Date(calendarData.calendar.year, calendarData.calendar.month,1)).getDay() ; //取得今年今月1日為禮拜幾 console.log(weekDay); let days = document.getElementsByTagName("td"); for (var i = 0; i <= 41; i++){ if (days[i].classList.contains("color")) days[i].classList.remove("color"); } for (var i = 1; i <= monthDays[calendarData.calendar.month]; i++){ days[weekDay + i - 1].innerHTML = i; } prevMonth = calendarData.calendar.month - 1; if (prevMonth == 0) prevMonth = 12; for (var i = (weekDay - 1), day = monthDays[prevMonth]; i >= 0; i--, day--){ days[i].innerHTML = day; days[i].classList.add("color"); } for (var i = (weekDay + monthDays[calendarData.calendar.month]), day = 1; i <= 41; i++, day++){ days[i].innerHTML = day; days[i].classList.add("color"); } } function previousMonth(){ console.log("Prev..."); calendarData.calendar.month--; if( calendarData.calendar.month == 0) { calendarData.calendar.year--; calendarData.calendar.month = 12; } fillInMonth(); } function nextMonth(){ console.log("Next..."); calendarData.calendar.month++; if( calendarData.calendar.month == 13) { calendarData.calendar.year++; calendarData.calendar.month = 1; } fillInMonth(); } document.onkeydown = function(e) { switch (e.keyCode) { case 37: previousMonth(); break; case 39: nextMonth(); break; } };
最後,將新增的程式片段整理至js/updateData.js。
2019/04/23 日期上下月處理(尚有bugs,月份加加減減超過邊界值)
function convert2Weekday(day){ switch(day){ case 0: return "Sunday"; case 1: return "Monday"; case 2: return "Tuesday"; case 3: return "Wednesday"; case 4: return "Thursday"; case 5: return "Friday"; case 6: return "Saturday"; } } function conert2MonthName(month) { switch(month){ case 0: return "January"; case 1: return "February"; case 2: return "March"; case 3: return "April"; case 4: return "May"; case 5: return "June"; case 6: return "July"; case 7: return "August"; case 8: return "September"; case 9: return "October"; case 10: return "November"; case 11: return "December"; } } function addOrdinalIndicator(date){ switch(date){ case 1: case 21: case 31: return date + "<sup>st</sup>"; case 2: case 22: return date + "<sup>nd</sup>"; case 3: case 23: return date + "<sup>rd</sup>"; default: return date + "<sup>th</sup>"; } } var date = new Date(); var year = date.getFullYear(); var month = date.getMonth(); function updateDateData(){ document.getElementById("cur-year").innerHTML = date.getFullYear(); document.getElementById("cur-month").innerHTML = conert2MonthName(date.getMonth()); document.getElementById("cur-date").innerHTML = addOrdinalIndicator(date.getDate()); document.getElementById("cur-day").innerHTML = convert2Weekday(date.getDay()); //星期幾, 0~6 document.getElementById("cal-year").innerHTML = date.getFullYear(); document.getElementById("cal-month").innerHTML = conert2MonthName(date.getMonth()); fillInMonth(year, month); } function fillInNextMonth(){ console.log("year:" + year + " month" + month); month++; fillInMonth(year, month); document.getElementById("cal-year").innerHTML = year; document.getElementById("cal-month").innerHTML = conert2MonthName(month); } function fillInPreviousMonth(){ console.log("year:" + year + " month" + month); month--; fillInMonth(year, month); document.getElementById("cal-year").innerHTML = year; document.getElementById("cal-month").innerHTML = conert2MonthName(month); } function fillInMonth(year, month) { let days = document.getElementsByTagName("td"); //將td標籤放入days物件集合中 date = new Date(year, month, 1); weekDay = date.getDay(); //計算出今年今月1日是星期幾… var monthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; //每個月的天數 if ( ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0) ) monthDays[1] = 29; //閏年2月是29天 //填這個月的日期 for (var i=weekDay, j=1; j <= monthDays[month]; i++, j++){ days[i].innerHTML = j; } //填上個月的日期 for (var i = (weekDay-1), day = monthDays[month-1]; i >=0; i--, day--){ days[i].innerHTML = day; days[i].classList.add("color"); //藍色背景 } //填下個月的日期 for (var i = (weekDay+monthDays[month]), day = 1; i <days.length; i++, day++){ days[i].innerHTML = day; days[i].classList.add("color"); //藍色背景 } //處理今日元素表格的灰色背景設定 if (document.getElementById("current-day")) { document.getElementById("current-day").removeAttribute("id"); } date = new Date(); current_date = date.getDate(); //今天是幾號 days[weekDay + current_date - 1].setAttribute("id", "current-day"); } document.onkeydown = function(e) { switch (e.keyCode) { case 37: fillInPreviousMonth(); break; case 39: fillInNextMonth(); break; } };
20190423 課堂影音