改造项目
场景
自己写个聚合首页,方便自己统一管理常用的网页工具,参考的是Mac OS的仪表盘,如下:
虽然短时间没法做到这么精美,但是起码功能得差不多吧,时钟与天气都已经OK,在做日历的时候觉得比较麻烦,就去CodePen找找看,便有了如此。
源码迁移
CodePen上的原项目本身难度不高,繁琐在理清楚日历逻辑(原作者逻辑),以及将此作者项目中关于DOM的操作转换成vue的模板操作。
先看逻辑
本月1号之前有可能存在上个月的尾巴(假如我们需要将日历方格全部填满)
本月内容以及当天的样式
本月最后一天后,也有可能会有下个月的月头
分别对应了原项目中这三个函数,原作者也有注释:
lastDayOfLastMonth 上个月最后一天,这里应该是原作者命名问题,应该是lastDayOfPreviousMonth
firstDayOfMonth 本月第一天
lastDateOfMonth 本月最后一天
i 是本月第几天,走了一个do while循环
// If not Sunday but first day of the month
// it will write the last days from the previous month
if ( i == 1 ) {
html += '
';var k = lastDayOfLastMonth - firstDayOfMonth+1;
for(var j=0; j < firstDayOfMonth; j++) {
html += '
' + k + '';k++;
}
}
上面的意思就是第一天时候把上个月尾巴给加到表格标签里面(最后统一加)
// Write the current day in the loop
var chk = new Date();
var chkY = chk.getFullYear();
var chkM = chk.getMonth();
if (chkY == this.currYear && chkM == this.currMonth && i == this.currDay) {
html += '
' + i + '';} else {
html += '
' + i + '';}
上面特殊处理的今天,其他本月内容都是常规加入,可以从class上面区分看出来。
// If not Saturday, but last day of the selected month
// it will write the next few days from the next month
if ( i == lastDateOfMonth ) {
var k=1;
for(dow; dow < 6; dow++) {
html += '
' + k + '';k++;
}
}
上面的意思就是当本月最后一天的时候,顺便把下个月的月头加进来。
漏了,每行的首尾控制
// If Sunday, start new row
if ( dow == 0 ) {
html += '
';}
// If Saturday, closes the row
if ( dow == 6 ) {
html += '
';}
这里说一下,因为日历是从周日到周六为一行,所以作者这里判断方案是Sunday与Saturday。
上面这些就是核心代码,当然还有下个月与上个月切换,不过就是清空当前日历再来一次,这些看源码即可,没有太多逻辑问题。
转vue
转起来难度不是很大,更多的是思维变化。
原项目是直接操作DOM,我们这里通过数据操作模板(姑且区分下),所以需要构建一个对象来承接每个”天“。
我们申明一个日历数组,由于日历是由若干个星期组成,所以我们就命名为:weeks,然后每个”天“给对象,属性如下:
{
// 哪天
label: [string],
// 是否今天
today: [boolean],
// 是否本月
current: [boolean],
}
那么我们的”天“会有这几种情况:
常规天
今天
上月或下月的天
{
// 哪天
label: [string],
// 是否本月
current: true,
}
{
// 哪天
label: [string],
// 是否今天
today: true,
// 是否本月
current: true,
}
{
// 哪天
label: [string],
}
接下来,我们把原逻辑里面对应的html,换成weeks,tr换成week(每次新建一个空数组),在周日或者第一天时候把week置空,在周六或本月最后一天把week闭合并且让weeks来push一下week,循环走完,我们一个月的关于weeks、week以及”天“的处理就完成了。
核心逻辑如下:
const y = this.year, m = this.month
let d = new Date()
// 本月第一天
, firstDayOfMonth = new Date(y, m, 1).getDay()
// 本月最后一天
, lastDateOfMonth = new Date(y, m + 1, 0).getDate()
// 上个月最后一天
, lastDayOfPreMonth = m === 0 ? new Date(y - 1, 11, 0).getDate() : new Date(y, m, 0).getDate()
let week = []
// 月第一=几天
let i = 1
do {
let dow = new Date(y, m, i).getDay()
// 周日则单独一行
if(dow === 0) {
week = []
}
// 每月第一天关于上个月尾数几天当月显示处理
else if(i === 1) {
let k = lastDayOfPreMonth - firstDayOfMonth + 1
for(let j = 0; j < firstDayOfMonth; j++) {
let obj = {
label: k,
}
week.push(obj)
k++
}
}
// 查询当天,高亮处理
let chk = new Date()
let chkY = chk.getFullYear()
let chkM = chk.getMonth()
if(chkY === this.year && chkM === this.month && i === this.day) {
week.push({
label: i,
// 本月
current: true,
today: true,
})
// 其他本月常规天
} else {
week.push({
label: i,
// 本月
current: true,
})
}
// 周六则闭合
if(dow === 6) {
this.weeks.push(week)
}
// 本月最后一天,处理下个月首几日在当月内显示
else if(i === lastDateOfMonth) {
let k = 1
for(dow; dow < 6; dow++) {
let obj = {
label: k,
}
week.push(obj)
k++
}
this.weeks.push(week)
}
i++
} while(i <= lastDateOfMonth)
注意跨年问题
最终效果