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