当前位置: 首页 > Web前端 > CSS

《前端每日实战》工作174号:日历

时间:2023-03-31 01:32:06 CSS

中秋国庆假期过后,我又要回来上班了。让我们制作一个日历来纪念它。效果预览按右侧“点击预览”按钮可在当前页面进行预览,点击链接可全屏预览。https://codepen.io/comehop??e/pen/mdEyWEv源码下载日常前端实战系列完整源码请到github下载:https://github.com/comehop??e/front-end-daily-challenges代码解读这个日历的开发过程是,在定义DOM结构之后,进行页面的整体布局,绘制日历表的外观,然后在上部布局当前日期,在日期表分别在下部。静态布局完成后,通过脚本动态生成日期元素,实现显示实时日期的动态日历。1.定义DOM结构dom的整体结构是一个名为.container的容器,包含2个元素,.today是当前日期,.calendar是日期表。

.today当前日期部分包含2个元素,.month表示当前月份,.day显示当前日期。9
October
.calcendar日期表格部分包含一个标题行.days和一个表.dates。表头按照英国习惯使用星期日作为一周的第一天;该表有6行,共显示42天,可以适应任何月份。表中的日期通过类名分为上月日期上月、当前日期当前日、下月日期下月。周日周一周二周三周四周五周六
272829301234567891011121314151617181920212223242526272829>30311234567二、页面整体布局和日历容器首先使用线性渐变,设置页面背景色为灰白过渡色body{margin:0;height:100vh;background-image:linear-gradient(tobottom,#eee,#ccc);}设置容器大小,使用相对单位em,使容器在页面居中。为了让容器可见,暂时用白色背景填充容器。body{display:flex;align-items:center;justify-content:center;}.container{width:32em;height:38em;font-size:14px;background-color:white;}效果如下图:注释掉背景-刚才临时定义的color属性,用锐渐变填充,达到上黄棕下白的效果。因为黄棕sandybrown是日历的主色调,后面会用到,所以定义为变量。然后在日历周围设置圆角,在底部添加双阴影,模拟多张日历纸叠放的效果。.container{/*背景颜色:白色;*/--main-color:sandybrown;背景图像:线性渐变(到底部,var(--main-color)50%,白色50%);边界半径:1em;box-shadow:02px1pxrgba(0,0,0,0.2),03px1pxwhite;}效果如下图:接下来画一个细节:圆环,用来连接上层和日历的下半部分。使用2个伪元素进行绘制,这样就不需要显式添加DOM元素,使用纯CSS实现装饰效果。两个表扣的样式相同,所以大部分代码是共享的,只是它们的位置不同,一个在日历的左侧,一个在日历的右侧。.container{position:relative;}.container::before,.container::after{content:'';位置:绝对;宽度:0.6em;高度:2.3em;背景色:白色;顶部:计算(50%-2.3em/2);边界半径:0.3em;盒子阴影:03px1pxrgba(0,0,0,0.3),0-1px1pxrgba(0,0,0,0.2);}。container::before{left:2em;}.container::after{right:2em;}效果如下图:至此,接近真实场景的日历轮廓绘制完成,接下来日历上显示的文本内容被布局。3.当前日期在上部的布局因为整个日历分为上下两部分,先令当前日期.today占据了上部50%的空间,所以表格.calendar自然被挤到了较低的部分。.today{height:50%;}效果如下图所示:因为整个日历使用相同的字体,所以在容器中定义了字体样式,使用了无衬线字体。.today的布局非常简单,使用字体大小、颜色和行间距等基本属性。.container{font-family:sans-serif;}.today{padding:3em;框大小:边框框;颜色:白色;}.today.day{字体大小:8em;行高:1em;-weight:bold;}.today.month{font-size:4em;行高:1em;text-transform:lowercase;}效果如下:4.日期表格布局的下部表格包括表头和表体两部分。设置它们的宽度并使用flex将它们垂直居中。.calendar{padding-top:3.5em;显示:弹性;弹性方向:列;align-items:center;}.calendar.days,.calendar.dates{width:28em;}header和table是一行7列,这里使用网格布局实现。.calendar.days,.calendar.dates{显示:网格;网格模板列:重复(7、1fr);行高:2em;text-align:center;}效果如下:表格已经成型,剩下的就是给文字上色了。表中有5个语义元素:表头、当前日期、本月日期、上月日期、下月日期。这些具有不同语义的元素通过CSS类名来区分。标题和当前日期使用主色,本月日期使用深灰色,上月日期和下月日期使用浅灰色。.calendar.days{color:var(--main-color);字体粗细:粗体;text-transform:uppercase;}.calendar.dates{color:dimgray;}.calendar.dates.previous-month,.calendar.dates.next-month{color:lightgray;}.calendar.dates.current-day{颜色:var(--主要颜色);font-weight:bold;}效果如下图所示:最后添加一个鼠标悬停停止特效,当鼠标悬停在日期上时,背景变灰,文字变白,使用transition实现一个平稳过渡。.calendar.datesspan:hover{背景颜色:浅灰色;color:white;}.calendar.datesspan{transition:0.3s;}至此,整个日历的静态布局就完成了。5.动态脚本程序的入口点是一个名为init的函数,它声明了一个Calendar类的实例,然后调用它的render()方法来渲染页面。functioninit(){letcalendar=newCalendar(newDate())calendar.render()}window.onload=initCalendar类接收一个日期参数来初始化年月日数据。render()方法调用renderDay()和renderMonth()分别呈现当前日期和当前月份。由于Date对象返回的月份属性是一个数字,为??了将其显示为英文月份名称,定义了一个数组来存储月份名称。letCalendar=function(date){letyear=date.getFullYear()letmonth=date.getMonth()letday=date.getDate()functionrenderDay(){document.querySelector('.day').textContent=day}functionrenderMonth(){constMONTHS=['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','November','December']document.querySelector('.month').textContent=MONTHS[month]}this.render=function(){renderDay()renderMonth()}}接下来,将渲染日期表。我们首先介绍一个日历库calendar-dates(github地址:https://dance2die.github.io/calendar-dates/),负责计算日期、星期、月份的关系,并输出一个对应关系给定年月日历数据。使用import语句导入库文件。importCalendarDatesfrom'https://cdn.jsdelivr.net/npm/calendar-dates@2.6.1/dist/calendardates.esm.js'注意对于使用import语句的脚本,需要在然后,在Calendar类中定义一个renderDates()函数来渲染日历列表。日历的获取方式可以参考官方文档,这里就不多说了。我觉得比较尴尬的是必须要用async/await的方式来调用。每个date都有date和type属性,date是日期值,type有3个值:previous、current、next,分别代表上个月、本月、下个月。我们使用这两个属性来处理日期元素的样式。最后,不要忘记在render()中调用renderDates()函数。异步函数renderDates(){constcalendarDates=newCalendarDates();constdomList=document.querySelector('.dates')domList.innerHTML=''for(constmetaofawaitcalendarDates.getDates(newDate(year,month))){letspan=document.createElement('span')跨度.textContent=meta.datespan.className=(meta.type=='current')?(元日期==天)?'current-day':'':meta.type+'-month'domList.append(span)}}this.render=function(){renderDay()renderMonth()renderDates()}大功告成!关于我张欧佩,网络笔名@comehop??e,20世纪末接触互联网,被Web的无穷魅力所俘获,从此奋战在Web开发的第一线。《前端每日实战》栏是我这几年练习项目式学习法的笔记。它使用项目驱动学习来展示从灵感到代码实现的完整过程。也可以作为前端开发的实践练习和开发参考。我的书《CSS3 艺术》由人民邮电出版社于2020年1月出版,全彩印刷。以100多个生动优美的实例,系统分析了与视觉效果相关的CSS重要语法,并附有近10小时的视频演示讲解。京东/天猫/当当网均有售。