美文网首页基础前端
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 制作中华万年历

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