[发财日历] 开发日志
前言
发财日历是一个由纯JS和CSS完成的一个小作品,主要是为了后面项目中作为一个组件复用
目前实现的功能有:
- 
显示日程 
- 
日程标记 
- 
高亮今日 
- 
日期选择 

链接
GitHub链接
预览链接
代码分析
整体代码结构
渲染加事件绑定
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | let currentTime = new Date()
 render(currentTime)
 
 g('#prevMonth').onclick = () => {...}
 
 g('#nextMonth').onclick = () => {...}
 
 g('#today').onclick = () => {...}
 
 function render(time) {...}
 
 function g(selector) {...}
 
 | 
事件绑定
需要给每个日期添加click事件,为了优化性能,使用事件委托代替给每个日期添加监听
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | days.addEventListener('click', (e) => {if (selectedLi) {
 selectedLi.classList.remove('calender-days-selected')
 }
 e.target.classList.add('calender-days-selected')
 selectedLi = e.target
 if (e.target.classList.contains('calender-days-hasEvents')) {
 const key = `${year}-${month}-${e.target.textContent}`
 const events = window.data[key]
 const eventFragment = document.createDocumentFragment()
 events.map(event => {
 const div = document.createElement('div')
 div.classList.add('events-item')
 div.textContent = event
 eventFragment.append(div)
 })
 g('#events').innerHTML = ""
 g('#events').append(eventFragment)
 } else {
 g('#events').innerHTML = "<div>无</div>"
 }
 })
 
 | 
避免频繁操作DOM
使用fragment,一次性装载所有日期
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | function render(time) {...
 function generateDays(year, month) {
 ...
 const fragment = document.createDocumentFragment()
 ...
 days.addEventListener('click', (e) => {
 ...
 if (...)) {
 ...
 const eventFragment = document.createDocumentFragment()
 events.map(event => {
 const div = document.createElement('div')
 ...
 eventFragment.append(div)
 })
 ...
 }
 })
 ...
 for (...) {
 const li = document.createElement('li')
 ...
 fragment.prepend(li)
 }
 
 for (...) {
 const li = document.createElement('li')
 ...
 fragment.append(li)
 }
 
 for (...) {
 ...
 const li = document.createElement('li')
 ...
 fragment.append(li)
 }
 days.append(fragment)
 }
 }
 
 | 
日程标记的实现
使用伪元素实现日程的绿色圆圈小标记
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | .calender-days > li.calender-days-hasEvents::after {content: '';
 border: 1px solid green;
 position: absolute;
 top: 4px;
 right: 4px;
 width: 8px;
 height: 8px;
 background: green;
 border-radius: 50%;
 }
 
 | 
日期计算逻辑
由于使用了原生JS,因此日期相关的API使用的也是原生的Date函数,比较难用
当月有多少天
下个月的月初 - 一天 = 当月的最后一天是几号 = 当月有多少天
| 12
 3
 
 | const lastDayOfCurrentMonth = new Date(new Date(year, month - 1 + 1, 1) - 86400 * 1000)const daysOfCurrentMonth = lastDayOfCurrentMonth.getDate()
 
 
 | 
周几如何计算
JS的getDay()是将周日作为0,周六作为6,因此为了更符合国人使用习惯,改成周一为1,周日为7
| 12
 3
 
 | if (weekdayOfFirstDayOfCurrentMonth === 0) {weekdayOfFirstDayOfCurrentMonth = 7
 }
 
 | 
上、下个月如何计算
当前月的第一天 - 一天 = 将当前时间拨到上个月
| 12
 3
 4
 
 | g('#prevMonth').onclick = () => {const firstDayOfCurrentMonth = new Date(currentTime.getFullYear(), currentTime.getMonth(), 1)
 render(new Date(firstDayOfCurrentMonth - 86400 * 1000))
 }
 
 | 
后记
简单的小组件,实现也很容易,主要作为后续项目的一个模块保存了下来,如果你有任何想法,欢迎留言告诉我~