js实现日历


Posted in Javascript onNovember 07, 2020

这周写自己的项目发现又用到日历了,加之自己毕业之后的第一个工作中遇到的任务也是需要写个日历(组员写了,我就不用写了)
今天就来好好折腾一下日历是怎么写的。

首先,我们看看 windows 的日历。发现总共有这么几个元素。先实现试试。

1.年份的选择、月份的选择
2.周一 ~ 周日(周日 ~ 周六)
3.日历格子 6*7 = 42

从数据的角度来分析日历的实现是比较简单的
1.我们需要显示一个当前时间的结构 - new Date()
2.我们需要显示当月的信息 - [星期(周一~周日),日期(1-[28,29,30,31])]
其中我们只要知道了每个月的 1日 是星期几,就能很容易地摆放后面的日子(万事开头难)。

  • 我们最多需要 6 行来显示我们的日期,因为要第一排如果只包含本月的一天 6(上个月的) + (1 + 4*7),这样就五行了,当月天数若大于 29,就显示不下了
  • 确定了 6 行之后,我们发现我们可能需要获取上个月,和下个月多出来的几天的摆放位置。
  • 不同年份的不同月的 2月份,我们知道它的日期是不同的,所以我们还需要判断 平年还是闰年。

3.显示上个月,下个月的切换。我们发现需要有个函数来帮我们更新日历。

分析完之后,让我们跟着 新增/修改 一些代码。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>Document</title>
<style>
 .week-item {
  display: inline-block;
  width: 80px;
  height: 40px;
  line-height: 40px;
  border: 1px solid sandybrown;
  text-align: center;
 }
 .date-item {
  display: inline-block;
  width: 80px;
  height: 40px;
  line-height: 40px;
  border: 1px solid beige;
  text-align: center;
 }
</style>
</head>
<body>
 <div class="wrapper">
  <div class="year-line">
   <button id="preMonth" class="year-prev">上一月</button>
   <button id="nowYear" class="year-now"></button>
   <button id="nowMonth"></button>
   <button id="nowDate"></button>
   <button id="nextMonth" class="year-next">下一月</button>
  </div>
  <div id="weekLine" class="week-line"></div>
  <div id="dateWrap" class="date-wrap"></div>
 </div>
</body>
<script>
 // 工具方法 - start
 // 1.为了获得每个月的日期有多少,我们需要判断 平年闰年[四年一闰,百年不闰,四百年再闰]
 const isLeapYear = (year) => {
  return (year % 400 === 0) || (year % 100 !== 0 && year % 4 === 0);
 };
 // 2.获得每个月的日期有多少,注意 month - [0-11]
 const getMonthCount = (year, month) => {
  let arr = [
   31, null, 31, 30, 
   31, 30, 31, 31,
   30, 31, 30, 31
  ];
  let count = arr[month] || (isLeapYear(year) ? 29 : 28);
  return Array.from(new Array(count), (item, value) => value + 1);
 };
 // 3.获得某年某月的 1号 是星期几,这里要注意的是 JS 的 API-getDay() 是从 [日-六](0-6),返回 number
 const getWeekday = (year, month) => {
  let date = new Date(year, month, 1);
  return date.getDay();
 };
 // 4.获得上个月的天数
 const getPreMonthCount = (year, month) => {
  if (month === 0) {
   return getMonthCount(year - 1, 11);
  } else {
   return getMonthCount(year, month - 1);
  }
 };
 // 5.获得下个月的天数
 const getNextMonthCount = (year, month) => {
  if (month === 11) {
   return getMonthCount(year + 1, 0);
  } else {
   return getMonthCount(year, month + 1);
  }
 };
 // 工具方法 - end
 let weekStr = '日一二三四五六';
 weekArr = weekStr.split('').map(item => '星期' + item);
 // 插入星期 dom
 let weekDomStr = '';
 let oFragWeek = document.createDocumentFragment();
 weekArr.forEach(item => {
  let oSpan = document.createElement('span');
  let oText = document.createTextNode(item);
  oSpan.appendChild(oText);
  oSpan.classList.add('week-item');
  oFragWeek.appendChild(oSpan);
 });
 let weekWrap = document.getElementById('weekLine');
 weekWrap.appendChild(oFragWeek);

 // 这里获得我们第一次的 数据 数组
 const updateCalendar = (year, month, day) => {
  if (typeof year === 'undefined' && typeof month === 'undefined' && typeof day === 'undefined') {
   let nowDate = new Date();
   year = nowDate.getFullYear();
   month = nowDate.getMonth();
   day = nowDate.getDate();
  }
  // 更新一下顶部的年月显示
  document.getElementById('nowYear').innerHTML = year;
  document.getElementById('nowMonth').innerHTML = month + 1;
  document.getElementById('nowDate').innerHTML = day;
  // 生成日历数据,上个月剩下的的 x 天 + 当月的 28(平年的2月)或者29(闰年的2月)或者30或者31天 + 下个月的 y 天 = 42
  let res = [];
  let currentMonth = getMonthCount(year, month);
  let preMonth = getPreMonthCount(year, month);
  let nextMonth = getNextMonthCount(year, month);
  let whereMonday = getWeekday(year, month);
  if (whereMonday === 0) {
   whereMonday = 7
  }
  // 感谢网友 luoyiming 的测试(哈哈!谢谢!):这里当 whereMonday 为 0 的时候会截取上月的所有数据
  let preArr = preMonth.slice(-1 * whereMonday)
  let nextArr = nextMonth.slice(0, 42 - currentMonth.length - whereMonday);
  res = [].concat(preArr, currentMonth, nextArr);
  // 上面经过我本人的测试是没有什么问题,接下来就是更新 dom 的信息的问题
  let hadDom = document.getElementsByClassName('date-item');
  if (hadDom && hadDom.length) {
   let domArr = document.getElementsByClassName('date-item');
   for (let i = 0; i < domArr.length; i++) {
    domArr[i].innerHTML = res.shift();
   }
  } else {
   // 如果之前没有结构的话
   let str = '';
   for (let i = 0; i < 6; i++) {
    str += '<div class="date-line">';
    for (let j = 0; j < 7; j++) {
     str += `<span class='date-item'>${res.shift()}</span>`;
     if (j === 6) {
      str += '</div>';
     }
    }
   }
   document.getElementById('dateWrap').innerHTML = str;
  }
 };

 updateCalendar();
 // 添加上一月,下一月事件
 let oPreButton = document.getElementById('preMonth');
 let oNextButton = document.getElementById('nextMonth');
 oPreButton.addEventListener('click', function () {
  let currentYear = +document.getElementById('nowYear').textContent;
  let currentMonth = +document.getElementById('nowMonth').textContent - 1;
  let currentDate = +document.getElementById('nowDate').textContent;
  if (currentMonth === 0) {
   updateCalendar(currentYear - 1, 11, currentDate);
  } else {
   updateCalendar(currentYear, currentMonth - 1, currentDate);
  }
 });
 oNextButton.addEventListener('click', function () {
  let currentYear = +document.getElementById('nowYear').textContent;
  let currentMonth = +document.getElementById('nowMonth').textContent - 1;
  let currentDate = +document.getElementById('nowDate').textContent;
  if (currentMonth === 11) {
   updateCalendar(currentYear + 1, 0, currentDate);
  } else {
   updateCalendar(currentYear, currentMonth + 1, currentDate);
  }
 });
</script>
</html>

发现用 dom 直接操作而不是通过 mvvm 框架实现确实还是比较蛋疼的,以下是这次实现的效果。

实现一个功能的时候,从数据的层面分析,有时候会比较容易理解

以上就是js实现日历的详细内容,更多关于js 日历的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
IE8 兼容性问题(属性名区分大小写)
Jun 04 Javascript
基于jQuery.Validate验证库知识点的详解
Apr 26 Javascript
使用JS+plupload直接批量上传图片到又拍云
Dec 01 Javascript
JavaScript中constructor()方法的使用简介
Jun 05 Javascript
js获取浏览器高度 窗口高度 元素尺寸 偏移属性的方法
Nov 21 Javascript
JavaScript组成、引入、输出、运算符基础知识讲解
Dec 08 Javascript
微信小程序 页面跳转传递值几种方法详解
Jan 12 Javascript
jQuery validate 验证radio实例
Mar 01 Javascript
详解vue 模拟后台数据(加载本地json文件)调试
Aug 25 Javascript
JavaScript设计模式之调停者模式实例详解
Feb 03 Javascript
jQuery AJAX应用实例总结
May 19 jQuery
原生js实现自定义滚动条
Jan 20 Javascript
工作中常用js功能汇总
Nov 07 #Javascript
解决VUE 在IE下出现ReferenceError: Promise未定义的问题
Nov 07 #Javascript
解决Element中el-date-picker组件不回填的情况
Nov 07 #Javascript
解决element-ui的下拉框有值却无法选中的情况
Nov 07 #Javascript
解决VUE项目使用Element-ui 下拉组件的验证失效问题
Nov 07 #Javascript
详解datagrid使用方法(重要)
Nov 06 #Javascript
VUE异步更新DOM - 用$nextTick解决DOM视图的问题
Nov 06 #Javascript
You might like
php调用google接口生成二维码示例
2014/04/28 PHP
PHP实现支持GET,POST,Multipart/form-data的HTTP请求类
2014/09/24 PHP
经典PHP加密解密函数Authcode()修复版代码
2015/04/05 PHP
PHP实现全角字符转为半角方法汇总
2015/07/09 PHP
PHP中有关长整数的一些操作教程
2019/09/11 PHP
Laravel 读取 config 下的数据方法
2019/10/13 PHP
Javascript继承(上)——对象构建介绍
2012/11/08 Javascript
JS判断客户端是手机还是PC的2个代码
2014/04/12 Javascript
一个JavaScript去除字符串末尾的空白实例代码
2014/09/22 Javascript
jquery控制背景音乐开关与自动播放提示音的方法
2015/02/06 Javascript
form+iframe解决跨域上传文件的方法
2016/11/18 Javascript
详解bootstrap的modal-remote两种加载方式【强化】
2017/01/27 Javascript
AngularJS中的拦截器实例详解
2017/04/07 Javascript
d3.js实现自定义多y轴折线图的示例代码
2018/05/30 Javascript
React 使用recharts实现散点地图的示例代码
2018/12/07 Javascript
vue 插件的方法代码详解
2019/06/06 Javascript
Javascript前端下载后台传来的文件流代码实例
2020/08/18 Javascript
[05:11]TI9战队采访——VIRTUSPRO
2019/08/22 DOTA
Django实现登录随机验证码的示例代码
2018/06/20 Python
对pandas中iloc,loc取数据差别及按条件取值的方法详解
2018/11/06 Python
python实现邮件自动发送
2019/08/10 Python
wxpython布局的实现方法
2019/11/01 Python
使用 css3 transform 属性来变换背景图的方法
2019/05/07 HTML / CSS
css3 旋转按钮 使用CSS3创建一个旋转可变色按钮
2012/12/31 HTML / CSS
美国半成品食材配送服务商:Home Chef
2018/01/25 全球购物
美国购买肉、鸭、家禽、鹅肝和熟食网站:D’Artagnan
2018/11/13 全球购物
毕业生怎样写好自荐信
2013/11/11 职场文书
《蚂蚁和蝈蝈》教学反思
2014/02/24 职场文书
小学生竞选班长演讲稿
2014/04/24 职场文书
企业口号大全
2014/06/12 职场文书
家长会欢迎词
2015/01/23 职场文书
入党自荐书范文
2015/03/05 职场文书
2015安全保卫工作总结
2015/04/25 职场文书
中国汉字听写大会观后感
2015/06/02 职场文书
GitHub上77.9K的Axios项目有哪些值得借鉴的地方详析
2021/06/15 Javascript
Python Pandas pandas.read_sql_query函数实例用法分析
2021/06/21 Python