[发财日历] 开发日志
前言
发财日历是一个由纯JS和CSS完成的一个小作品,主要是为了后面项目中作为一个组件复用
目前实现的功能有:
-
显示日程
-
日程标记
-
高亮今日
-
日期选择
![](https://img.bald3r.wang/img/20220726153656.png)
链接
GitHub链接
预览链接
代码分析
整体代码结构
渲染加事件绑定
1 2 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事件,为了优化性能,使用事件委托代替给每个日期添加监听
1 2 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,一次性装载所有日期
1 2 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) } }
|
日程标记的实现
使用伪元素实现日程的绿色圆圈小标记
1 2 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函数,比较难用
当月有多少天
下个月的月初 - 一天 = 当月的最后一天是几号 = 当月有多少天
1 2 3
| const lastDayOfCurrentMonth = new Date(new Date(year, month - 1 + 1, 1) - 86400 * 1000) const daysOfCurrentMonth = lastDayOfCurrentMonth.getDate()
|
周几如何计算
JS的getDay()
是将周日作为0,周六作为6,因此为了更符合国人使用习惯,改成周一为1,周日为7
1 2 3
| if (weekdayOfFirstDayOfCurrentMonth === 0) { weekdayOfFirstDayOfCurrentMonth = 7 }
|
上、下个月如何计算
当前月的第一天 - 一天 = 将当前时间拨到上个月
1 2 3 4
| g('#prevMonth').onclick = () => { const firstDayOfCurrentMonth = new Date(currentTime.getFullYear(), currentTime.getMonth(), 1) render(new Date(firstDayOfCurrentMonth - 86400 * 1000)) }
|
后记
简单的小组件,实现也很容易,主要作为后续项目的一个模块保存了下来,如果你有任何想法,欢迎留言告诉我~