美文网首页基础前端
React 制作中华万年历

React 制作中华万年历

作者: CondorHero | 来源:发表于2019-07-26 19:15 被阅读0次
万年历

在前端工作中,日历应该还是比较常见的,虽然不是特别的难但还是有点算法在里面的,想不通就做不出来。上面这个案例完全是手工写的,所以样式可能看着有点不太好看,但是我的审美也就到这个地步了。嘿嘿!

看到这个案例,脑子中应该立马想到 九九乘法表 那个案例的写法。九九乘法表的案例写在了这篇文章的最后,React 语法基本使用介绍核心思想就是二维数组。

每个日历页面都是六行七列,分别显示着上个月,这个月,和下个月的日期。转换成代码就是一个大数组,里面包含四十二个元素。接下来该探讨怎么求得分别对应日期。

我 react 代码对应的目录结构



Calendar 是 APP 的组件,APP是 main 的组件,main.js 打包放入 index.html。

在main.js 的变量存储区创建时间得到当前的年份和月份。

this.state = {
    year : (new Date()).getFullYear(),
    // 月份是从零开始的所以加一
    month : (new Date()).getMonth() + 1
}

在 calendar.js 里面构建业务,现在先让 四十二 个数字进去构建一个日历页面。

//一个大数组存放四十二个元素
var createDateArr = [];
// 上月的天数
const predays = new Date(this.props.year,this.props.month - 1,0).getDate();
// 本月的天数
const nowdays = new Date(this.props.year,this.props.month,0).getDate();
// 本月的第一天是星期几,是几就留上个月几天在日历上
const nowweek = new Date(this.props.year,this.props.month - 1,1).getDay();
// 根据本月第一天星期几计算上个月末尾有几天在本月开头的显示
let count = nowweek;
//当count == 0 时,也就是上个月没有天数放在当前页面,这时下个月会出现十几天不美观
// 所以我们进行调整,让上个月占满第一行
if(count == 0)count = 7;

while(count){
    count--;
    createDateArr.push({
        // 根据月份查出上个月是不是还是这一年不是就减一,这里的年份主要给农历用
        year : this.props.month > 1 ? this.props.year : this.props.year - 1,
        month : this.props.month > 1 ? this.props.month - 1 : 12,
        day : predays - count
    });
}
// 把本月的天数在放进数组
for(let i = 1;i <= nowdays;i++){
    createDateArr.push({
        year : this.props.year,
        month : this.props.month,
        day : i
    });
}

上面的算法思想就是先算出本月第一天星期几,星期几对应的数字就是上个月有几天展现出来。例如今天 2019 年 7 月 1 号 星期一,那上个月就留一天。因为后来还的添加农历,所以必须的记住上个月的年份,就像一月份的上个月是去年的十二月,这点的注意。

然后把本月的天数在放进数组,这时就剩下下个月开头的天数了。补齐四十二天,同时也要注意年份和月份的问题。

// 日历一共42天不够补齐下个月开头作为本月的结尾
let k = 1;
while(createDateArr.length!=42){
    createDateArr.push({
        year : this.props.month < 12 ? this.props.year : this.props.year + 1,
        month : this.props.month < 12 ? this.props.month + 1 : 0,
        day : k++
    });
}

核心的代码就是上面创建一个大数组的过程,接下来把大数组和表格标签结合在一起,有点二维数组的思想,来创建表格放进数据。

const dateArr = ()=>{
    var arr = [];
    for(let i = 0;i < 6;i++){
        let temp = [];
        for(let j = 0;j < 7;j++){
            // 引入动态类,来判断当天这一天来加个背景色
            temp.push(<td key={j} className = {classnames({
                bgc:(new Date()).getFullYear() == createDateArr[i * 7 + j].year && (new Date()).getMonth()+1 == createDateArr[i * 7 + j].month && (new Date()).getDate() == createDateArr[i * 7 + j].day? 1 : 0
            })}>{
                (()=>{
                        let o = createDateArr[i * 7 + j];
                        let y = o.year;
                        let m = o.month;
                        let d = o.day;
                        let lunar = solarLunar.solar2lunar(y,m,d).dayCn;
                        let term = solarLunar.solar2lunar(y,m,d).term;
                        // 如果有节气就显示节气,否则就显示阴历
                    return <div><h4>{o.day}</h4><p className={classnames({bg:term})}>{term ? term : lunar}</p></div>
                })()
                // IIFE 提取<h4>{createDateArr[i * 7 + j].day}</h4>{solarLunar.solar2lunar(createDateArr[i * 7 + j].year, createDateArr[i * 7 + j].month, createDateArr[i * 7 + j].day).dayCn}
            }</td>)
        }
        arr.push(<tr key={i}>{temp}</tr>);
    }
    return arr;
}

基本上就能实现了,这时的在 APP.js 里面进行事件绑定,达到动态更改日历的效果,至于农历实现就要借入 npm 社区的 solarlunar 这个阴阳历转换了,很简单 npm 安装,引包在表格的 td 这个标签处实现。其他的都是边边角的问题了。不会的话请看下方我的源代码。

源代码数据:

App.js 文件:

import React,{Component} from "react";
import Calendar from "./calendar/Calendar";

export default class App extends Component {
    constructor(){
        super();
        this.state = {
            year : (new Date()).getFullYear(),
            // 月份是从零开始的所以加一
            month : (new Date()).getMonth() + 1
        }
    }
    changeYear(e){
        this.setState({
            year : parseInt(e.target.value)
        })
    }
    changeMonth(e){
        this.setState({
            month : parseInt(e.target.value)
        })
        console.log(parseInt(e.target.value))
    }
    render(){
        var selectYearArr = [];
        for(let i = 1900;i < 2100;i++){
            selectYearArr.push(i);
        }
        var selectMonthArr = [1,2,3,4,5,6,7,8,9,10,11,12];
        return (
                <div>
                    <main>
                        <span>
                            <select value = {`${this.state.year} 年`} onChange = {(event)=>{
                        this.changeYear(event)
                    }}>
                        {selectYearArr.map((item,index)=><option key={index}>{item} 年</option>)}
                            </select>
                        </span>
                        <span>
                            <select value = {`${this.state.month} 月`} onChange = {(event)=>{
                            this.changeMonth(event)
                        }}>
                            {selectMonthArr.map((item,index)=><option key={index}>{item} 月</option>)}
                            </select>
                        </span>
                        <Calendar year = {this.state.year} month = {this.state.month}></Calendar>
                    </main>
                </div>
            )
    }
}

calendar.js文件

import React,{Component} from "react";
import solarLunar from 'solarLunar';
import classnames from "classnames";
export default class Calendar extends Component{
    constructor(){
        super();
    }
    render(){
            //一个大数组存放四十二个元素
            var createDateArr = [];
            // 上月的天数
            const predays = new Date(this.props.year,this.props.month - 1,0).getDate();
            // 本月的天数
            const nowdays = new Date(this.props.year,this.props.month,0).getDate();
            // 本月的第一天是星期几,是几就留上个月几天在日历上
            const nowweek = new Date(this.props.year,this.props.month - 1,1).getDay();
            // 根据本月第一天星期几计算上个月末尾有几天在本月开头的显示
            let count = nowweek;
            //当count == 0 时,也就是上个月没有天数放在当前页面,这时下个月会出现十几天不美观
            // 所以我们进行调整,让上个月占满第一行
            if(count == 0)count = 7;

            while(count){
                count--;
                createDateArr.push({
                    // 根据月份查出上个月是不是还是这一年不是就减一,这里的年份主要给农历用
                    year : this.props.month > 1 ? this.props.year : this.props.year - 1,
                    month : this.props.month > 1 ? this.props.month - 1 : 12,
                    day : predays - count
                });
            }
            // 把本月的天数在放进数组
            for(let i = 1;i <= nowdays;i++){
                createDateArr.push({
                    year : this.props.year,
                    month : this.props.month,
                    day : i
                });
            }
            // 日历一共42天不够补齐下个月开头作为本月的结尾
            let k = 1;
            while(createDateArr.length!=42){
                createDateArr.push({
                    year : this.props.month < 12 ? this.props.year : this.props.year + 1,
                    month : this.props.month < 12 ? this.props.month + 1 : 0,
                    day : k++
                });
            }
        const dateArr = ()=>{
            var arr = [];
            for(let i = 0;i < 6;i++){
                let temp = [];
                for(let j = 0;j < 7;j++){
                    // 引入动态类,来判断当天这一天来加个
                    temp.push(<td key={j} className = {classnames({
                        bgc:(new Date()).getFullYear() == createDateArr[i * 7 + j].year && (new Date()).getMonth()+1 == createDateArr[i * 7 + j].month && (new Date()).getDate() == createDateArr[i * 7 + j].day? 1 : 0
                    })}>{
                        (()=>{
                                let o = createDateArr[i * 7 + j];
                                let y = o.year;
                                let m = o.month;
                                let d = o.day;
                                let lunar = solarLunar.solar2lunar(y,m,d).dayCn;
                                let term = solarLunar.solar2lunar(y,m,d).term;
                                // 如果有节气就显示节气,否则就显示阴历
                            return <div><h4>{o.day}</h4><p className={classnames({bg:term})}>{term ? term : lunar}</p></div>
                        })()
                        // IIFE 提取<h4>{createDateArr[i * 7 + j].day}</h4>{solarLunar.solar2lunar(createDateArr[i * 7 + j].year, createDateArr[i * 7 + j].month, createDateArr[i * 7 + j].day).dayCn}
                    }</td>)
                }
                arr.push(<tr key={i}>{temp}</tr>);
            }
            return arr;
        }
        // 日历的头部
        var headArr = ["日","一","二","三","四","五","六"];
        return (
                <div>
                    <table>
                        <thead>
                            <tr>
                                {headArr.map((item,index)=><td key = {index}>{item}</td>)}
                            </tr>
                        </thead>
                        <tbody>
                            {dateArr()}
                        </tbody>
                    </table>
                </div>
            )
    }
}

样式:less.less

body{
    *{
        margin:0;
        padding:0;
    }
    @bg:background-color;
    @{bg}:#f6f6f6;
    main{
        margin:30px auto;
        width: 424px;
        background-color:#5eaeff;
    }
    span {
        display:inline-block;
        padding:20px;
    }
    span:nth-child(2)::after{
        content:"中华万年历";
        color: #fff;
        padding-left: 40px;
        font-size: 20px;
    }
    select {
        width: 70px;
        height: 20px;
        border:1px solid #909;
        vertical-align: bottom;
    }
    table{
        border-collapse: collapse;
        background-color:white;
        border: 2px solid #5aacff;
        cursor:pointer;
        tbody td {
            height: 60px;
            width: 60px;
            font-size:14px;
            vertical-align:top;
            color: #999;
            text-align:center;
        }
        tbody tr {
            border-top: 1px solid #c8cacc;
        }
        thead td{
            text-align:center;
            height: 40px;
            border-bottom: 1px solid #5af;
        }
        h4{ 
            color:#090;
            padding:6px 0;
        }
        .bg{
            color:#fb0;
        }
        .bgc{
            background-color:#0f0;
        }
    }
}

相关文章

  • React 制作中华万年历

    在前端工作中,日历应该还是比较常见的,虽然不是特别的难但还是有点算法在里面的,想不通就做不出来。上面这个案例完全是...

  • React Native 多组件方案

    出于各方面考量一般 React Native 不会制作大型组件,这意味着 React Native 不会制作完整 ...

  • 洛格择日提醒

    @所有人,回重庆了!洛格先生,再次提醒,我们择日子,一定不能只看万年历及通书。我把今天有中华万年历的批语...

  • 学习足迹

    2015.7-2017.5<学习纪录于中华万年历,断断续续,只有读书的封面,没有读书笔记,; 2017.3.1至今...

  • 2021-02-19

    中华万年历技术支持网址:有问题的可以留言。邮箱地址:youyib@qq.com[mailto:youyib@qq....

  • 利用JS制作万年历

    利用JS制作万年历 我们知道,万年历在人们的生活中是在平常不过的一种东西了,那么怎样用JS来实现在网页中展示一个与...

  • Flutter + TensorFlow + YOLO 制作 N

    本文是 TensorFlow + YOLO + React Native 制作 Not Hotdog App 的 ...

  • iOS Peacock广告、统计系统简介及重构

    简介 名称来历 Peacock最早为中华万年历提供广告开屏使用,联想到孔雀开屏,所以命名Peacock。后来随着业...

  • 中国黄河底下,有一座非常伟大的工程,美国:中国人真疯狂

    文/大农 已有上万年历史的黄河,为中华文明进步作出了巨大贡献,它也被誉为中华儿女的摇篮。 在成河的历史过程中,运动...

  • React-Native App启动页制作(安卓端)

    原文地址:React-Native App启动页制作(安卓端) 这篇文章是根据开源项目react-native-...

网友评论

    本文标题:React 制作中华万年历

    本文链接:https://www.haomeiwen.com/subject/ywvdrctx.html