當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
JavaScript日历(es5版本)
生活随笔
收集整理的這篇文章主要介紹了
JavaScript日历(es5版本)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
近期在知乎上看到這么一個帖子,題主說自己JavaScript都學完了,結果老師留的作業還是不會寫,就是寫一個日歷的插件,結果樓下一堆大牛出現了,百度的阿里的紛紛站出來發表自己的看法,有人認為簡單,有人認為其實細化不簡單,于是出于好奇,自己也來動手寫了一下。雖說現如今各種優秀的UI框架層出不窮,都會自帶calendar和datepick這種日歷相關的組件,而且無論是適配還是視覺效果都做得相當nice,可能都不會用到自己寫的,但是還是打算動手,因為date對象也是js里面的重點。
?
第一版:純js實現通過切換月份和年份,來展示不同的日歷頁面,實際上是根據當前年月,來進行頁面的重繪,所以頁面渲染是一個函數,所需參數就是當前選中的年份和月份。
const render = (month, year) => {
};
render();
首先,日歷除去首行day有幾行? 一共6行,Math.ceil((31 - 1) / 7 + 1) = 6
三塊組成:上月剩余,本月,下月開始
1,上月剩余 首先要知道本月1號是周幾(x),然后從周日到x的天數就是上月剩余天數,從幾號到幾號,需要了解本月是幾月,來推算出上月月末是幾號,其實也就是上月有多少天。
2,本月 只需知道當月是幾月,當月多少天,然后按順序排。
3,下月開始 只需要知道下月1號是周幾,然后42個數字還剩多少,從1排到最后就可以了 代碼部分: HTML: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Date Picker</title><link rel="stylesheet" type="text/css" href="css/index.css"></link> </head> <body><input id="textInput" class="textInput" type="text" placeholder="選擇日期" /><div id="datePicker" class="datePicker datePickerHide"><div class="dateHeader"><span id="yearLeft" class="left headerMid"><<</span><span id="monthLeft" class="left headerMid page"><</span><span id="changeDateHead" class="page"><span id="changeYear" class="headerMid col"><span id="dateYear"></span><span>年</span></span><span id="changeMonth" class="headerMid col"><span id="dateMonth"></span><span>月</span></span></span><span id="changeYearHead" class="page headerMid col" style="display: none"><span id="changeYearFirst"></span><span>年</span><span>-</span><span id="changeYearLast"></span><span>年</span></span><span id="changeMonthHead" class="page headerMid col" style="display: none"><span id="backChangeYearPage"></span><span>年</span></span><span id="yearRight" class="right headerMid">>></span><span id="monthRight" class="right headerMid page">></span></div><div class="dateMain"><div id="firstPage" class="page firstPage" style="display: block"><div class="dateDay"><span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span></div><div id="dateBody" class="dateBody"></div></div><div id="secondPage" class="page secondPage" style="display: none"></div><div id="thirdPage" class="page secondPage" style="display: none" οnclick="chooseMonth()"><span><em id="month-1" index='1'>1月</em></span><span><em id="month-2" index='2'>2月</em></span><span><em id="month-3" index='3'>3月</em></span><span><em id="month-4" index='4'>4月</em></span><span><em id="month-5" index='5'>5月</em></span><span><em id="month-6" index='6'>6月</em></span><span><em id="month-7" index='7'>7月</em></span><span><em id="month-8" index='8'>8月</em></span><span><em id="month-9" index='9'>9月</em></span><span><em id="month-10" index='10'>10月</em></span><span><em id="month-11" index='11'>11月</em></span><span><em id="month-12" index='12'>12月</em></span></div></div></div> </body> <script src="js/index.js"></script> </html>
js部分:
// 默認是當天 var chosenDate = new Date(),year = chosenDate.getFullYear(),month = chosenDate.getMonth() + 1,date = chosenDate.getDate(),lastDateId = '', // 掛到全局下去lastYearId = '',lastMonthId = '',firstNum = 0;window.onload = function(){renderFirstPage(year, month, date);// input框獲取焦點時日歷顯示var datePicker = getIdDom('datePicker');getIdDom('textInput').onfocus = function(){datePicker.className = 'datePicker datePickerShow';}/* 以上是第一部分頁面展示 *//* 二級頁面 */var renderSecondPage = function(firstNum){var lastNum = firstNum + 9; // 二級頁面末尾數字getIdDom('changeYearFirst').innerHTML = firstNum;getIdDom('changeYearLast').innerHTML = lastNum;var yearTemplate = ``;for (var i = firstNum; i < lastNum + 1; i++) {if (i == year) {// 當前選中年yearTemplate += `<span><em id="year-${i}" οnclick="chooseYear(this, ${i})" style="background-color: #39f;color: #fff">${i}</em></span>`} else {yearTemplate += `<span><em id="year-${i}" οnclick="chooseYear(this, ${i})">${i}</em></span>`}}getIdDom('secondPage').innerHTML = yearTemplate;}var reRenderSecondPage = function(){var yearStr = year.toString();var yearLastLetter = yearStr[yearStr.length-1]; // 末尾數firstNum = year - Number(yearLastLetter); // 二級頁面首位數字renderSecondPage(firstNum);}reRenderSecondPage();getIdDom("backChangeYearPage").innerHTML = year; // 三級頁面年份// click事件集中寫// 上一年下一年,上一月下一月的點擊事件clickFn('yearLeft', function(){if (getIdDom('changeYearHead').style.display != 'none') {// 此時是二級頁面,選年份if (firstNum - 10 < 1) {// 首位年份不能小于1return}firstNum -= 10;renderSecondPage(firstNum);} else {if (year - 1 < 1) {// 年份不能小于1return}year--;renderFirstPage(year, month, date);getIdDom("backChangeYearPage").innerHTML = year;reRenderSecondPage();}});clickFn('monthLeft', function(){if (month < 2) {// 1月month = 12;year--;} else {month--;}renderFirstPage(year, month, date)});clickFn('yearRight', function(){if (getIdDom('changeYearHead').style.display != 'none') {// 此時是二級頁面,選年份firstNum += 10;renderSecondPage(firstNum);} else {year++;renderFirstPage(year, month, date);getIdDom("backChangeYearPage").innerHTML = year;reRenderSecondPage();}});clickFn('monthRight', function(){if (month > 11) {// 12月month = 1;year++;} else {month++;}renderFirstPage(year, month, date)});clickFn('changeYear', function(){var pagesArr = Array.from(document.querySelectorAll('.page'));pagesArr.forEach(function(item){item.style = 'display: none'});reRenderSecondPage();changeStyle('secondPage', 'display: block');changeStyle('changeYearHead', 'display: inline-block');}); // 點擊年份切換至二級頁面clickFn('changeMonth', function(){var pagesArr = Array.from(document.querySelectorAll('.page'));pagesArr.forEach(function(item){item.style = 'display: none'});if (lastMonthId !== '') {// 非第一次點擊getIdDom(lastMonthId).style = "";}changeStyle("month-" + month, 'background-color: #39f;color: #fff');lastMonthId = 'month-' + month;changeStyle('thirdPage', 'display: block');changeStyle('changeMonthHead', 'display: inline-block');})clickFn('changeMonthHead', function(){// 切回年份選擇var pagesArr = Array.from(document.querySelectorAll('.page'));pagesArr.forEach(function(item){item.style = 'display: none'});changeStyle('secondPage', 'display: block');changeStyle('changeYearHead', 'display: inline-block');reRenderSecondPage();})document.getElementsByTagName('html')[0].onclick = function(e){// 這里模擬失去焦點事件var name = e.target.nodeName;if (name == 'BODY' || name == 'HTML') {datePicker.className = 'datePicker datePickerHide';}}}function getIdDom(id){return document.getElementById(id) } // 根據id獲取dom節點function clickFn(id, fn) {getIdDom(id).onclick = fn; } // 封裝一下click方法function renderFirstPage(year, month, date = 1){var datePage = []; // 最終展示頁面的所有日期合集 // 第一部分,上月月末幾天// 首先要知道上月一共多少天var getAlldays = (year, month) => {if (month <= 7) {// 1-7月if (month % 2 === 0) {// 偶數月if (month === 2) {// 2月特殊if ((year % 400 == 0) || ( year % 4 == 0 && year % 100 != 0)) {// 閏年var alldays = 29} else {var alldays = 28}} else {var alldays = 30}} else {// 奇數月var alldays = 31}} else {// 8-12月if (month % 2 === 0) {// 偶數月var alldays = 31} else {var alldays = 30}}return alldays}; // alldays表示某年某月的總天數var lastMonthAllDays = getAlldays(year, month - 1); // 上月天數var chosenFirstMonthDay = new Date(year, month - 1, 1).getDay(); // 當月1號周幾var datePageTemplate = ``;var num = 0;for (var i = lastMonthAllDays - chosenFirstMonthDay + 1; i < lastMonthAllDays + 1; i++ ) {datePageTemplate += `<span id="lastMonth"><em id="last-${i}" οnclick="chooseDate(this, 'last-${i}', ${year}, ${month}, ${i})">${i}</em></span>`;num++;}// 第二部分,當月總天數var chosenMonthAllDays = getAlldays(year, month); // 當月天數var time = new Date();var a = time.getFullYear(),b = time.getMonth() + 1,c = time.getDate(); // 用來記錄當天時間for(var i = 1; i < chosenMonthAllDays + 1; i++) {var chosenDateObj = {year: year,month: month,date: i};if (i === c && year === a && month === b) {// 今天日期高亮datePageTemplate += `<span id="today" class="currentMonth"><em id="today-${i}" οnclick="chooseDate(this, 'today-${i}', ${year}, ${month}, ${i})" class="today">${i}</em></span>`;} else {datePageTemplate += `<span id="currentMonth" class="currentMonth"><em id="cur-${i}" οnclick="chooseDate(this, 'cur-${i}', ${year}, ${month}, ${i})">${i}</em></span>`;}num++;}// 第三部分,剩余天數for (var i = 1; i < 43 - num; i++) {var chosenDateObj = {year: year,month: month,date: i};datePageTemplate += `<span id="nextMonth"><em id="nex-${i}" οnclick="chooseDate(this, 'nex-${i}', ${year}, ${month}, ${i})">${i}</em></span>`;}var templateString = `${datePageTemplate}`;var innerFn = function(id, content) {getIdDom(id).innerHTML = content};innerFn('dateYear', year);innerFn('dateMonth', month);innerFn('dateBody', templateString);}function chooseDate(item, index, year, month, date) {event.stopPropagation();if (lastDateId !== '') {// 非第一次點擊getIdDom(lastDateId).style = "";}// 選中項樣式改變,并且將input的日期修改lastDateId = index;item.style = "background-color: #39f;color: #fff";getIdDom("textInput").value = year + '-' + month + '-' + date; }function chooseYear(item, thisYear) {event.stopPropagation();if (lastYearId !== '') {// 非第一次點擊if (getIdDom(lastYearId)) {// 存在已經跨頁面了,但是id不存在了getIdDom(lastYearId).style = "";}} else {// 第一次點擊getIdDom('year-' + year).style = "";}lastYearId = 'year-' + thisYear;year = thisYear;item.style = "background-color: #39f;color: #fff";var pagesArr = Array.from(document.querySelectorAll('.page'));pagesArr.forEach(function(item){item.style = 'display: none'});if (lastMonthId !== '') {// 非第一次點擊getIdDom(lastMonthId).style = "";}changeStyle("month-" + month, 'background-color: #39f;color: #fff');lastMonthId = 'month-' + month;getIdDom("backChangeYearPage").innerHTML = year;changeStyle('changeMonthHead', 'display: inline-block');changeStyle('thirdPage', 'display: block'); }function chooseMonth(){var target = event.target;if (target.nodeName === 'EM') {// 表示當前點擊的為em節點if (lastMonthId !== '') {// 非第一次點擊getIdDom(lastMonthId).style = "";} else {// 第一次點擊getIdDom('month-' + month).style = "";}month = parseInt(target.innerHTML);lastMonthId = 'month-' + month;target.style = "background-color: #39f;color: #fff";renderFirstPage(year, month, date);// 展示首頁var pagesArr = Array.from(document.querySelectorAll('.page'));pagesArr.forEach(function(item){item.style = 'display: none'});changeStyle('firstPage', 'display: block');changeStyle(['changeDateHead', 'monthLeft', 'monthRight'], 'display: inline-block');} }// 判斷對象類型 function isType(type){return function(obj){return toString.call(obj) == '[object ' + type + ']';} }// 改變display屬性 function changeStyle(ids, styles){var isString = isType('String'),isArray = isType('Array');if (isString(ids)) {getIdDom(ids).style = styles;} else if (isArray(ids)) {ids.forEach(function(item){getIdDom(item).style = styles;})} }
css部分:
* {margin: 0;padding: 0; }*, :after, :before {box-sizing: border-box; }body {font-family: Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,\\5FAE\8F6F\96C5\9ED1,Arial,sans-serif; }.textInput {position: relative;display: block; }.datePicker {width: 216px;margin: 10px;color: #c3cbd6;border-radius: 4px;box-shadow: 0 1px 6px rgba(0,0,0,.2);transform-origin: center top 0px;transition: all .2s ease-in-out;position: absolute;left: 0px;top: 16px; } .datePickerHide {opacity: 0; }.datePickerShow {opacity: 1; }.dateHeader {height: 32px;line-height: 32px;text-align: center;border-bottom: 1px solid #e3e8ee; }.left, .right {display: inline-block;width: 20px;height: 24px;line-height: 26px;margin-top: 4px;text-align: center;cursor: pointer;color: #c3cbd6;-webkit-transition: color .2s ease-in-out;transition: color .2s ease-in-out; }.left {float: left;margin-left: 10px; }.right {float: right;margin-right: 10px; }.dateMain {margin: 10px; }.dateDay {line-height: normal;font-size: 0;letter-spacing:normal; }span {display: inline-block;text-align: center;font-size: 12px; }.dateDay span {line-height: 24px;width: 24px;height: 24px;margin: 2px; }.dateBody span {width: 28px;height: 28px;cursor: pointer; }.dateBody span em {display: inline-block;position: relative;width: 24px;height: 24px;line-height: 24px;margin: 2px;font-style: normal;border-radius: 3px;text-align: center;transition: all .2s ease-in-out; }.dateBody span.currentMonth {color: #657180; }.today:after {content: '';display: block;width: 6px;height: 6px;border-radius: 50%;background: #39f;position: absolute;top: 1px;right: 1px; }.currentMonth em:hover {background-color: #e1f0fe; }.col {color: #657180; }.headerMid {cursor: pointer; }.headerMid:hover {color: #39f; }/* second */ .secondPage {width: 196px;font-size: 0; }.secondPage span {display: inline-block;width: 40px;height: 28px;line-height: 28px;margin: 10px 12px;border-radius: 3px;cursor: pointer; }.secondPage span em {display: inline-block;width: 40px;height: 28px;line-height: 28px;margin: 0;font-style: normal;border-radius: 3px;text-align: center;transition: all .2s ease-in-out;color: #657180; }.secondPage span em:hover {background-color: #e1f0fe; }
GitHub項目地址:https://github.com/Yanchenyu/DatePicker
項目寫完了,但其實發現里面存在大量的DOM操作以及環境污染,這個對性能的損耗是相當大的,寫得越多越發現狀態難以管理,都只能掛到全局下去,所以打算再寫一套React版本的。 end?
轉載于:https://www.cnblogs.com/yanchenyu/p/8425141.html
總結
以上是生活随笔為你收集整理的JavaScript日历(es5版本)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kotlin的2017年总结与2018年
- 下一篇: mybatis使用foreach实现sq