JS工具库moment —— 实现日历

moment

moment是一个js工具库,这个库中封装的是日期时间的方法,功能很全面。可以去moment官网看看,它的中文文档介绍的也很详细,主要是看一下方法的使用。附上官网地址:moment.js官网
在这里插入图片描述

日历案例

模仿的是win10自带的日历,但是功能没有很全面,简单的实现了上下翻更新的效果,选择年份的功能没有实现呢。
简单说下,日历的逻辑问题。
从当前月出发,必须直到当前月的天数,必须知道当前月第一天是星期几。
只有知道了天数和第一天是星期几,才能知道第一天的位置在哪,要显示几天。核心点就是解决这两点,在解决了天数和星期的问题之后,当前月减去1就是上个月,当前月加上1就是下个月。那整体效果就出来了。
获取某月的天数,获取某月第一天是周几等等,moment已经为我们封装好了这些方法,直接使用就可以了。

案例中需要使用的方法

以下方法都是在moment()返回对象身上的方法
获取当前日期和时间:moment()
获取某月的天数:daysInMonth()
获取某月的第一天:startOf(‘month’)
获取某天是星期几:weekday()
增加时间:add(Number, String)
减去时间:subtract(Number, String)
设置中文的语言环境:locale(‘zh-ch’)
获取星期数据:weekdaysMin()
显示格式:format()。这个是使用最多用处最大的方法,它的参数是令牌,令牌不同日期和时间显示不同。

案例效果

在这里插入图片描述

案例整体的功能分布

  • 即时的时间
  • 即时的日期
  • 获取星期
  • 生成日历
  • 日历对应的农历

结构和样式的话比较好搭,最终显示的部分都是通过js部分渲染出来的,就不做解释,后面会把代码附上。

  1. 即时的时间
    获取当下的时间,设置定时器每1S执行一次。
//中文语言环境
moment.locale('zh-cn');
// 一、即时的时间
function nowTime() {
    timeDate.innerHTML = moment().format('LTS');
}
nowTime();
setInterval(nowTime, 1000);
  1. 即时的日期
    这里牵扯到的还有农历日期,放到后面再补充
timeDay.innerHTML = moment().format("LL")
  1. 获取星期
    获取星期的数据,遍历添加结构,渲染视图。
// 二、星期
let weekArr = moment.weekdaysMin(true); // 根据语言环境获取不同的星期数组
let weekStr = '';
weekArr.forEach(function (ele) {
    weekStr += `<span>${ele}</span>`;
});
week.innerHTML = weekStr;
  1. 获取某月的天数以及某月第一天是周几
    封装两个方法,用来获取月的天数和第一天星期几,方法的参数都是moment对象。
// 日历逻辑:
// 必须知道当前月的天数,当前月第一天星期几
// 某月的天数
function getMonthDays(momentObj) {
    return momentObj.daysInMonth();
}
// console.log(getMonthDays(moment())); // 当前月最后一天的数字  
// console.log(getMonthDays(moment().subtract(1, 'month'))); // 当前月的上一个月最后一天的数字
// console.log(getMonthDays(moment().add(1, 'month'))); // 当前月的下一个月最后一天的数字


// 某月第一天的星期
// startOf 第一天
// weekday 星期几
function getWeekDays(momentObj) {
    return momentObj.startOf('month').weekday(); // 
}
// console.log(getWeekDays(moment())); // 当月
// console.log(getWeekDays(moment().add(1, 'month'))); // 下个月
  1. 生成日历
// 三、生成日历
let today = moment();
setDate(today);

封装生成日历方法
首先获取当前月的天数,当前月第一天是周几。英文环境下:[“Su”, “Mo”, “Tu”, “We”, “Th”, “Fr”, “Sa”];中文环境下:[“一”, “二”, “三”, “日”, “五”, “六”, “日”]。
获取周几返回的是数组的索引。

  • 上一个月:上个月在本月显示的天数 刚好等于获取星期得到的天数;
  • 下一个月:下月在本月显示的天数是出去当前月天数+上月显示天数剩余的天数;
  • 当前月:获取天数,同时要判断当月当天突出显示。
function setDate(m) {
    // 获得当前月的天数  和 第一天的星期数
    let curDays = getMonthDays(m); // 当前天数
    let curWeek = getWeekDays(m.clone()); // 当前月第一天的星期(索引值)
    let upDays = getMonthDays(m.clone().subtract(1, 'month')); // 上月的天数
    // console.log(curDays, curWeek, upDays);

    // 生成的结构
    let strDate = '';
    // 下个月的起始日期
    let nextFirstDate = 0;
    for (let i = 0; i < 42; i++) {
        // 1. 当前月的上一个月
        if (i < curWeek) { // 返回的索引值刚好是上月在当月显示的天数
            strDate = `
            <li class="speical">
                <span>${upDays}</span>
                <span></span>
            </li>${strDate}`;
            upDays--; // 倒叙显示   30 31
        } else if (i >= curDays + curWeek) { //去除掉当月天数+上月天数就是下月天数
            // 2. 当前月的下一个月:除去当月最后一天+上月的几天剩余的是下月开始计算
            // curWeek 返回值刚好是上月占用的天数
            nextFirstDate++;
            strDate += `
            <li class="speical">
                <span>${nextFirstDate}</span>
                <span></span>
            </li>`;
        } else {
            // 3. 当前月
            // i-curWeek+1 为当前月的天数
            // date()获取日期号
            // m.date() == i - curWeek + 1说明这一天是当月当天,添加样式
            let currentClass = m.date() == i - curWeek + 1 ? 'current' : '';
            if (m.year() != moment().year() || m.month() != moment().month()) {
                currentClass = '';
            }
            strDate += `
            <li class = ${currentClass}>
                <span>${i-curWeek+1}</span>
                <span></span>
            </li>`;

        }
    }
    timeYM.innerHTML = m.format("YYYY年MMM"); // 更新日历头部的年月
    dateList.innerHTML = strDate; // 渲染日历
}
  1. 上下翻页功能
    向上是上个月,向下是下个月。核心点就是添加和删除一个月份
// 四、按钮事件
upBtn.onclick = function () {
    // 点击切换为上个月
    setDate(today.subtract(1, 'month'));
}

downBtn.onclick = function () {
    // 点击切换为下个月
    setDate(today.add(1, 'month'));
}
  1. 生成农历
    农历也是用到一个库文件:calendar.js,这个文件就是转换公历、阴历的。
    这里封装一个方法,通过公历获取对应的阴历日期
//获取农历
// 参数:年 月 日
function getDayCn(year, month, date) {
	// 把calendar文件中的calendar对象挂在了window对象上,通过属性调用calendar
	// 这样不会更改源文件
    let dayCn = window.calendar.solar2lunar(year, month, date);
    let result = '';

    if (dayCn.IDayCn == '初一') { //如果是月初的话,换成这个月的名字
        result = dayCn.IMonthCn;
    } else if (dayCn.Term) { //如果有节气的话,换成节气
        result = dayCn.Term;
    } else if (dayCn.festival) { //如果有节日的话,换成节日
        result = dayCn.festival;
    } else if (dayCn.lunarFestival) { //如果有中国传统的节日的话,换成传统节日(春节、元宵节、端午节)
        result = dayCn.lunarFestival;
    } else {
        result = dayCn.IDayCn; //都没有的话就是农历
    }
    return result;
}

修改时间下面的日期,也就是加上农历日期

// 即时的日期
var dayCn = window.calendar.solar2lunar(moment().year(), moment().month() + 1,
    moment().date()); //取到农历日期
// 拼接农历日期
timeDay.innerHTML = moment().format("LL") +
    ' ' + dayCn.IMonthCn + dayCn.IDayCn + ' ' + (dayCn.Term ? dayCn.Term : ''); // 年月

添加日历中对应的农历日期,这里我只把不同月拼接字符串的部分放上。

注意:moment().month()返回值比实际月小1,比如本月是7月,moment().month()返回6,刚好是上月,moment().month()+1是本月,moment().month()+2是下月。

// 1. 当前月的上一个月
        if (i < curWeek) {
        // 上月 getDayCn(m.year(),m.month(),upDays)
        // m.month()返回值与实际值少1
            strDate = `
            <li class="speical">
                <span>${upDays}</span>
                <span>${getDayCn(m.year(),m.month(),upDays)}</span>
            </li>${strDate}`;
            upDays--;
        } else if (i >= curDays + curWeek) { // 31+2=33
            // 2. 当前月的下一个月:除去当月最后一天+上月的几天剩余的是下月开始计算
            // curWeek 返回值刚好是上月占用的天数
            strDate += `
            <li class="speical">
            <span>${nextFirstDate}</span>
            <span>${getDayCn(m.year(),m.month()+2,nextFirstDate)}</span>
            </li>`;
            nextFirstDate++;
        } else {
            // 3. 当前月
            // i-curWeek+1 为当前月的天数
            let currentClass = m.date() == i - curWeek + 1 ? 'current' : '';
            if (m.year() != moment().year() || m.month() != moment().month()) {
                currentClass = '';
            }
            strDate += `
            <li class = ${currentClass}>
                <span>${i-curWeek+1}</span>
                <span>${getDayCn(m.year(),m.month()+1,i-curWeek+1)}</span>
            </li>`;

到此,整个日历就完成了。其实用原生js也可以写,但是比较麻烦,使用js工具库写就相对比较简单了。整个日历的核心逻辑就是天数跟第一天是星期几,解决了这个核心点,日历的问题就解决了。
在没写之前确实决定很难实现,在了解之后,明白了日历的逻辑,实现起来就好多了。
加油!!!!

日历代码

结构

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>日历</title>
    <link rel="stylesheet" href="./index.css">
</head>

<body>
    <div class="calenderBox">
        <div class="title">
            <p class="timeHMS">10:18:06</p>
            <p class="timeYMD">2020729日 六月初九</p>
        </div>
        <div class="content">
            <div class="control">
                <div class="timeYM">20207</div>
                <div class="arrow">
                    <span class="up"></span>
                    <span class="down"></span>
                </div>
            </div>
            <div class="dateList">
                <div class="week">
                    <!-- <span></span>
                    <span></span> 
                    <span></span>
                    <span></span>
                    <span></span>
                    <span></span>
                    <span></span> -->
                </div>
                <ul>
                    <!-- <li><span>28</span><span>初八</span></li>
                    <li class="speical"><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li class="current"><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li>
                    <li><span>28</span><span>初八</span></li> -->
                </ul>
            </div>

        </div>
    </div>

    <script src="./js/moment-with-locales.js"></script>
    <script src="./js/calendar.js"></script>
    <script src="./js/index.js"></script>
</body>

</html>

样式:

* {
    margin: 0;
    padding: 0;
}

body {
    background: #333;
    margin: 0;
}

ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

.calenderBox {
    width: 420px;
    margin: 100px auto 0;
    border: 1px solid #444;
    background-color: #2d2d2d;
}

/* title */
.title {
    padding: 20px 35px;
    border-bottom: 1px solid #535353;
}

.title .timeHMS {
    font-size: 40px;
    color: #efefef;
}

.title .timeYMD {
    font-size: 14px;
    color: #999;
}

/* content */
.content {
    color: #efefef;
    padding: 20px 0;
}

.control {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 35px;
    height: 25px;
    margin-bottom: 15px;
    /* border: 1px solid red;
    box-sizing: border-box; */
}

.arrow {
    padding-right: 5px;
}

.control .up,
.control .down {
    display: inline-block;
    transform: scaleX(1.7);
    font-size: 20px;
    margin-left: 33px;
    cursor: pointer;
}

.dateList {
    padding: 0 20px;
}

.week {
    display: flex;
}

.week span {
    height: 40px;
    flex: 1 1 auto;
    text-align: center;
}

.dateList ul {
    display: flex;
    flex-wrap: wrap;
}

.dateList ul li {
    width: 54px;
    height: 54px;
    text-align: center;

    display: flex;
    flex-direction: column;
    justify-content: center;
}

.dateList ul li span:nth-child(2) {
    font-size: 14px;
}

.dateList li.speical {
    color: #6e6e6e;
}

.dateList li.current {
    background-color: #0078d7;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值