欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

程序员文章站 2024-01-01 21:49:22
一、React生命周期 一个组件从出生到消亡,在各个阶段React提供给我们调用的接口,就是生命周期。 生命周期这个东西,必须有项目,才知道他们干嘛的。 1.1 Mouting阶段【装载过程】 这个阶段在组件上树的时候发生,依次是: App.js: Child组件: 1.2 Updating阶段【更 ......

一、react生命周期

一个组件从出生到消亡,在各个阶段react提供给我们调用的接口,就是生命周期。

生命周期这个东西,必须有项目,才知道他们干嘛的。

前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发


1.1 mouting阶段【装载过程

这个阶段在组件上树的时候发生,依次是:

constructor(props)     构造函数        作用:初始化state值,此时可访问props、发ajax请求
componentwillmount()     组件将要上树    作用:常用于根组件中的引用程序配置,不能做任何涉及dom的事情完成一些计算工作
render()                渲染组件        作用:创建虚拟dom,组建的ui样式
componentdidmount()    组件已经上树    作用:启动ajax调用,加载组件的数据,还能用ref得到dom,添加事件监听

 

app.js

import react from "react";
import child from "./child.js";
export default class app extends react.component{
    constructor(){
        super();
        this.state = {
            a:100,
            isshow:true
        }
    }
    render(){
        return <div>
            <button onclick={()=>{this.setstate({a:this.state.a+1})}}>改变a值</button>
            <button onclick={()=>{this.setstate({isshow:!this.state.isshow})}}>
显示/隐藏组件
</button>
            { this.state.isshow ? <child a={this.state.a}></child> : null }
        </div>
    }
};

 

child组件:  

import react from 'react';
export default class child extends react.component {
    constructor(){
        super();
        console.log("我是constructor构造函数");
        this.state = {
            m : 200
        }
    }
    //组件将要上树
    componentwillmount(){
        console.log("我是componentwillmount");
    }
    //组件已经上树
    componentdidmount(){
        console.log("我是componentdidmount");
    }

    render(){
        console.log("我是render");  
        return (
            <div>
                <button onclick={()=>{this.setstate({m:this.state.m+1})}}>改变m值</button>
                子组件的m值:{this.state.m},
                子组件接收a值:{this.props.a}
            </div>
        );
    }
}

 


1.2 updating阶段【更新过程

当组件的props改变或state改变的时候触发,依次是:

componentwillreceiveprops(nextprops)

当收到新的props的时候触发

 

shouldcomponentupdate(nextprops,nextstate)

【门神函数】当组件stateprops改变时触发,这个函数需要return true或者false,表示是否继续进updating阶段。如return false,视图将不再更新,大致是为了增加效率。

 

componentwillupdate(nextprops, nextstate)

当组件stateprops改变时触发,用来在update的时候进行一些准备。

 

render()渲染方法,创建虚拟dom

 

componentdidupdate(prevprops, prevstate)

当组件stateprops改变时触发,用来进行一些更新的验证。组件更新完成后调用,此时可以获取最新的dom节点,用来验证信息的。

 

updating阶段中,绝对不允许改变stateprops,否则会死循环。


 

1.3 unmounting阶段【卸载过程】

就一个函数:componentwillunmount()组件将要下树。

完整的child.js子组件:

import react from 'react';
export default class child extends react.component {
    constructor() {
        super();
        console.log("我是constructor构造函数")
        this.state = {
            m:200
        }
    }
    //组件将要上树
    componentwillmount(){
        console.log("我是componentwillmount将要上树")
    }
    //组件已经上树
    componentdidmount(){
        console.log("我是componentdidmount已经上树")
    }

//************updataing阶段【更新阶段】************** */
// 当组件的props或state改变时触发
componentwillreceiveprops(nextprops){
    console.log("更阶段的:componentwillreceiveprops", nextprops)
}
shouldcomponentupdate(nextprops, nextstate) {
    console.log("更阶段的:shouldcomponentupdate", nextprops, nextstate)
    return true;
}
componentwillupdate(nextprops, nextstate){
    console.log("更阶段的:componentwillupdate", nextprops, nextstate)
}
componentdidupdate(prevprops, prevstate){
    console.log("更阶段的:componentdidupdate", prevprops, prevstate)
}

//组件下树
    componentwillunmount(){
        console.log("componentwillunmount组件下树了");
}

    render(){
        console.log("我是render")
        return <div>
            <button onclick={()=>{ this.setstate({m: this.state.m + 1 })}}>改变m值</button>
            <h2>子组件的m值:{this.state.m}</h2>
            <h2>子组件接收父组件a值:{this.props.a}</h2>
        </div>
    }
}

 

上树阶段:
    constructor
    componentwillmount
    render
    componentdidmount
更新阶段:
    componentwillreceiveprops
    shouldcomponentupdate
    componentwillupdate
    render
    componentdidupdate
下树阶段
    componentwillunmount

二、virtual domdiff算法(理论知识)

react会在内存中存储一份dom的镜像,当有render发生的时候,此时会在内存中用diff算法进行最小差异比较,实现最小的更新。

virtual domreactvue中的一个很重要的概念,在日常开发中,前端工程师们需要将后台的数据呈现到界面中,同时要能对用户的操作提供反馈,作用到ui上…… 这些都离不开dom操作。但是我们知道,频繁的dom操作会造成极大的资源浪费,也通常是性能瓶颈的原因。于是reactvue引入了virtual domvirtual dom的核心就是计算比较改变前后的dom区别,然后用最少的dom操作语句对dom进行操作

 

现在需要将下图左边的dom结构替换成右边的结构,这种情景在实战项目中是经常会遇到的。但是如果直接操作dom的话,进行移除的话可能就是四次删除,五次插入,这种消耗是很大的但是使用virtual dom,那就是比较两个结构的差异,发现仅仅改变了四次内容,一次插入这种消耗就小很多,无非加上一个比较的时间。

 

前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

react告诉我们的是在内存中维护一颗和页面一样的dom树,这颗dom树不是真正渲染在html中的,而是放在内存中的,因此修改它将会特别的快,并且资源消耗也少很多,当我们render一个页面的时候首先先将我们最新的dom去和内存中的这棵虚拟dom树去做对比(脏检查),然后对比出差异点,然后再用这棵虚拟dom差异的部分去替换真正dom树中的一部分。

 

这就是所谓的 virtual dom 算法。包括几个步骤:

  javascript 对象结构表示 dom 树的结构;然后用这个树构建一个真正的 dom 树,插到文档当中。

 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异。

 2所记录的差异应用到步骤1所构建的真正的dom树上,视图就更新了。

 

virtual dom 本质上就是在 js dom 之间做了一个缓存。这个概念就和我们当初学操作系统一样,可以类比 cpu 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 dom 这么慢,我们就在它们 js dom 之间加个缓存。cpujs)只操作内存(virtual dom),最后的时候再把变更写入硬盘(dom)。

app.js

import react from "react";
export default class app extends react.component {
    constructor() {
        super();
        this.state = {
            a : 100
        }
    }
    componentdidmount(){
$(this.refs.list).find("li").css("position","relative").animate({"left":500},5000)
    }
    render(){
        console.log("我是render函数")
        return <div>
            <button onclick={()=>{this.setstate({a : this.state.a + 1})}}>按我</button>
            <ul ref="list">
                <li>a</li>
                <li>b</li>
                <li>{this.state.a}</li>
                <li>d</li>
            </ul>
        </div>
    }
}

当某一个组件状态、属性被更改时,它的子组件、孙组件都会被重新渲染,virtual dom也将会计算这些组件的dom更新。

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发


三、日历组件

3.1业务

日选择视图

年选择视图

月选择视图

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

 


3.2划分组件

组件划分就是根据第一直观印象即可,按结构、功能独立进行划分。

最大组件canlendar,里面有数据yearmonthdate

点击一个按钮,可以显示弹出层,弹出层的组件名:canlendar_menu

下辖五个组件,五个组件都兄弟:

chooserdate

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

chooseryear

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

choosermonth

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

pickerdate

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

pickeryear

 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发

 

 

所有的组件不需要对兄弟组件负责,只需要对最大组件的数据负责。

 

【先实现日历视图】

index.html

<html>
<head>
    <title>日历组件</title>
    <link rel="stylesheet" href="css/style.css" />
</head>
<body>
    <div id="app"></div>
    <script type="text/javascript" src="lib/jquery-2.2.4.min.js"></script>
    <script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>

创建app/components/canlendar/index.js文件,这是最大的组件。

import react from "react";
export default class canlendar extends react.component {
    constructor() {
        super();
    }
    render() {
        return <div>
            我是canlendar组件
        </div>
    }
}

 

app/app.js引入canlendar最大组件

import react from "react";
import canlendar from "./components/canlendar";
export default class app extends react.component {
    constructor() {
        super();
     
    }
    render(){
        return <div>
            <div>
                出生日期:<canlendar></canlendar>
            </div>
        </div>
    }
}

 

开始写app/components/canlendar/index.js

import react from "react";
import canlendarmenu from "./canlendarmenu.js";
export default class canlendar extends react.component {
    constructor() {
        super();
        this.state = {
            year : 2018 ,
            month : 8 ,
            date : 8,
            isshowmenu : false
        }
    } 
    render() {
        return <div classname="canlendar">
            <div classname="inputbox">
                {this.state.year}年{this.state.month}月{this.state.date}日
            </div>
            {
                this.state.isshowmenu 
                ?
                <canlendarmenu
                    year={this.state.year}
                    month={this.state.month}
                    date={this.state.date}
                ></canlendarmenu>
                :
                null
            }
        </div>
    }
}

css样式:

*{margin:0;padding:0;}
.canlendar{position: relative;}
.canlendar .inputbox{
    width: 150px;height: 20px;border: 1px solid #bdbdbd;
    border-radius:2px;position:relative;font-size:13px;
    padding:0 10px;color:#424242;line-height: 20px;
}
.canlendar .inputbox::before{
    content:"";position: absolute;right:0;top:0;
    width:20px;height:20px;background: #f5f5f5;
}

 

开始写app/components/canlendar/canlendarmenu.js弹出层

import react from "react";
import pickerdate from "./pickerdate.js";
import chooserdate from "./chooserdate.js";
export default class canlendarmenu extends react.component {
    constructor() {
        super();
    }
render() {
    //解构得到年、月、日
    const {year, month, date} = this.props;
        return <div classname="canlendar_menu">
            <pickerdate year={year} month={month}></pickerdate>
            <chooserdate year={year} month={month} date={date}></chooserdate>
        </div>
    }
}

css样式:

.canlendar .canlendar_menu{
    position: absolute;top: 26px;left:0;z-index: 999;
    width:360px; height:260px;
    border: 1px solid #bdbdbd;
    box-shadow: 0px 0px 8px #00000036;
    border-radius: 5px;background:white;
}

 

app/components/canlendar/pickerdate.js

import react from "react";
export default class pickerdate extends react.component {
    constructor() {
        super();
    }
    render() {
        const {year, month} = this.props;
        return <div classname="picker">
            <div classname="left">
                <a classname="btn" href="###">上1月</a>
            </div>
            <div classname="center">
                <a href="###">{year}</a>年
                <a href="###">{month}</a>月
            </div>
            <div classname="right">
                <a classname="btn" href="###">下1月 </a>
            </div>
        </div>
    }
}

css样式:

.canlendar .picker{padding-top:10px;overflow: hidden;margin-bottom: 13px;}
.canlendar .picker .left{float: left;width:33.33%;text-align: center;}
.canlendar .picker .right{float:left;width:33.33%;text-align: center;}
.canlendar .picker .center{
    float: left;width:33.33%;text-align: center;font-size: 18px;font-weight: bold;
}
.canlendar .picker .btn{
    padding:4px 10px;background: #2196f3;font-size: 12px;
    border-radius: 4px;text-decoration: none;color: white;
}
.canlendar .chooserdate{color:#333;font-size: 12px;}
.canlendar .chooserdate span{display: block;}
.canlendar .chooserdate table{
    width:100%;text-align:center;line-height: 14px;border-collapse:collapse;
}
.canlendar .chooserdate span.cd{font-size: 10px;}
.canlendar .chooserdate table td{padding-bottom: 2px;cursor: pointer;}
.canlendar .chooserdate table th{line-height: 26px;}
.canlendar .chooserdate table td.gray{color: #c1bcbc;}
.canlendar .chooserdate table td.cur{background-color: #ffcdd2;}

 

 

app/components/canlendar/chooserdate.js

import react from "react";
export default class chooserdate extends react.component {
    constructor() {
        super();
    }
    render() {
        return <div classname="chooserdate">
            <table>
                <tbody>
                    <tr>
                        <th>日</th>
                        <th>一</th>
                        <th>二</th>
                        <th>三</th>
                        <th>四</th>
                        <th>五</th>
                        <th>六</th>
                    </tr>
                    <tr>
                        <td>
                            <span>31</span>
                            <span classname="cd">初一</span>
                        </td>
                    </tr>
                    tr*6>td*7
                </tbody>
            </table>
        </div>
    }
}
import react from "react";
import { solar2lunar } from "solarlunar";
import classnames from "classnames";
export default class chooserdate extends react.component {
    constructor() {
        super();
    }
    //显示表格
    showtable(){
        const {year , month , date} = this.props;
        //三要素
        var thismonth1day = new date(year, month - 1 , 1).getday();
        var thismonthdateamount = new date(year, month, 0).getdate();
        var prevmonthdateamount = new date(year, month - 1, 0).getdate();
    
        var arr = [];
        //上个月的尾巴
        while(thismonth1day--){
            var d = prevmonthdateamount--;
            var sl = solarlunar.solar2lunar(year, month - 1, d);
            arr.unshift({
                "d" : d,
                "cd": sl.term || sl.daycn,
            })
        }
        //本月
        var count = 0;
        while (thismonthdateamount--){
        count++;
            var d = count;
            var sl = solarlunar.solar2lunar(year, month, d);
            arr.push({
                "d": d,
                "cd": sl.term || sl.daycn,
            });
            
        }
        //下月开头
        var nextcount = 0;
        while(arr.length != 42){
        nextcount++;
            var d = nextcount;
            var sl = solarlunar.solar2lunar(year, month + 1, d);
            arr.push({
                "d": d,
                "cd": sl.term || sl.daycn,
            });
        }
    //表格上树显示
        var domarr = [];
        for(var i = 0;  i < arr.length / 7; i++){
            domarr.push(
                <tr key={i}>
                    {
                        // 数组会自动展开
                        arr.slice(i * 7, i * 7 + 7).map((item, index)=>{
                            return <td key={index}>
                                <span>{item.d}</span>
                                <span classname="cd">{item.cd}</span>
                            </td>
                        })
                    }
                </tr>
            )
        }
        return domarr;
    }

    render() {
        return <div classname="chooserdate">
            <table>
                <tbody>
                    <tr>
                        <th>日</th>
                        <th>一</th>
                        <th>二</th>
                        <th>三</th>
                        <th>四</th>
                        <th>五</th>
                        <th>六</th>
                    </tr>
                    {this.showtable()}
                </tbody>
            </table>
        </div>
    }
}

 

app/components/canlendar/index.js实现切换上月、下月

import react from "react";
import canlendarmenu from "./canlendarmenu.js";
export default class canlendar extends react.component {
    constructor() {
        super();
        this.state = {
            year : 2018 ,
            month : 8 ,
            date : 8,
            isshowmenu : false
        }
    } 
    setshowmenu(isshowmenu){
        this.setstate({isshowmenu});
    }
    setyear(year){
        this.setstate({ year });
    }
    setmonth(month){
        this.setstate({ month });
    }
    setdate(date){
        this.setstate({date});
    }
    render() {
        return <div classname="canlendar">
            <div classname="inputbox" onclick={()=>{this.setstate({"isshowmenu" : true})}}>
                {this.state.year}年{this.state.month}月{this.state.date}日
            </div>
            {
                this.state.isshowmenu 
                ?
                <canlendarmenu
                    year={this.state.year}
                    month={this.state.month}
                    date={this.state.date}
                    setyear={this.setyear.bind(this)}
                    setmonth={this.setmonth.bind(this)}
                    setdate={this.setdate.bind(this)}
                    setshowmenu={this.setshowmenu.bind(this)}
                ></canlendarmenu>
                :
                null
            }   
        </div>
    }
}

 

然后通过app/components/canlendar/canlendarmenu.js继续往下传

import react from "react";
import pickerdate from "./pickerdate.js";
import chooserdate from "./chooserdate.js";
export default class canlendarmenu extends react.component {
    constructor() {
        super();
    }
render() {
    //解构得到年、月、日
    const {year, month, date, setyear, setmonth, setdate, setshowmenu} = this.props;
        return <div classname="canlendar_menu">
          <pickerdate setyear={setyear} setmonth={setmonth}></pickerdate>
          <chooserdate setyear={setyear} setmonth={setmonth} setdate={setdate}></chooserdate>
        </div>
    }
}

 

canlender/pickerdate.js

import react from "react";
export default class pickerdate extends react.component {
    constructor() {
        super();
    }
    //下一月
    nextmonth(){
        //如果不是12月,此时月份加1 
        if(this.props.month != 12){
            this.props.setmonth(this.props.month + 1);
        }else{
            //如果是12月,此时月份变为1,年加1
            this.props.setmonth(1);
            this.props.setyear(this.props.year + 1);
        }   
    }
    //上一月
    prevmonth(){
        if(this.props.month != 1) {
            this.props.setmonth(this.props.month - 1);
        }else{
            this.props.setmonth(12);
            this.props.setyear(this.props.year - 1);
        }
    }
    render() {
        const {year, month} = this.props;
        return <div classname="picker">
            <div classname="left">
                <a classname="btn" href="###" onclick={()=>{this.prevmonth()}}>上1月</a>
            </div>
            <div classname="center">
                <a href="###">{year}</a>年
                <a href="###">{month}</a>月
            </div>
            <div classname="right">
                <a classname="btn" href="###" onclick={()=>{this.nextmonth()}}>下1月</a>
            </div>
        </div>
    }
}

 

完善app/components/canlendar/chooserdate.js

添加类名,点击单元格切换

import react from "react";
import { solar2lunar } from "solarlunar";
import classnames from "classnames";
export default class chooserdate extends react.component {
    constructor() {
        super();
    }
    
    //点击某一个小格格改变年月日
    clicktd(d, isprevmonth, isnextmonth){
        this.props.setdate(d);    //设置日子
        this.props.setshowmenu(false);    //关闭菜单
        if(isprevmonth){
            var dd = new date(this.props.year, this.props.month - 2, d);    //月份要重算
            this.props.setmonth(dd.getmonth() + 1);    //改变月份
            this.props.setyear(dd.getfullyear());    //改变年
        }else if(isnextmonth){
            var dd = new date(this.props.year, this.props.month, d);    //月份要重算
            this.props.setmonth(dd.getmonth() + 1);    //改变月份
            this.props.setyear(dd.getfullyear());    //改变年
        }
    }

    //显示表格
    showtable(){
        const {year , month , date} = this.props;
        //三要素
           .......

        var arr = [];
        //上个月的尾巴
        var count = thismonth1day;
        while(count--){
            var d = prevmonthdateamount - count;
            var sl = solar2lunar(year, month - 1, d);
            arr.push({
                "d" : d,
                "cd": sl.term || sl.daycn,
                "gray" : true ,
                "cur" : false ,
                "prevmonth" : true
            })
        }
        //本月
        var count = 1;
        while (count <= thismonthdateamount){
            var d = count;
            var sl = solar2lunar(year, month, d);
            arr.push({
                "d": d,
                "cd": sl.term || sl.daycn,
                "gray": false ,
                "cur": date == d
            });
            count++;
        }
        //下月开头
        var count = 1;
        while(arr.length != 35 && arr.length != 42){
            var d = count++;
            var sl = solar2lunar(year, month + 1, d);
            arr.push({
                "d": d,
                "cd": sl.term || sl.daycn,
                "gray" : true ,
                "cur" : false ,
                'nextmonth' : true
            });
        }

        var domarr = [];
        for(var i = 0 ;  i < arr.length / 7 ; i++){
            domarr.push(
                <tr key={i}>
                    {
                        // 数组会自动展开
                        arr.slice(i * 7, i * 7 + 7).map((item, index) => {
                            return <td 
                                key={index} 
                                classname={classnames({"gray":item.gray, "cur":item.cur})}
                                onclick={()=>{this.clicktd(item.d, item.prevmonth, item.nextmonth)}}
                            >
                                <span classname="d">{item.d}</span>
                                <span classname="cd">{item.cd}</span>
                            </td>
                        })
                    }
                </tr>
            )
        }
        return domarr;
    }
    render() {
        return <div classname="chooserdate">
            <table>
                ...   
            </table>
        </div>
    }
}

 

app/components/canlendar/canlendarmenu.js切换视图

import react from "react";
import pickerdate from "./pickerdate.js";
import chooserdate from "./chooserdate.js";
import chooserdate from "./chooseryear.js";
export default class canlendarmenu extends react.component {
    constructor() {
        super();
    }
render() {
    //解构得到年、月、日
    const {year, month, date} = this.props;
        return <div classname="canlendar_menu">
            <pickerdate year={year} month={month}></pickerdate>
            {/*<chooserdate year={year} month={month} date={date}></chooserdate>*/}
        <chooseryear year={year} setyear={setyear}></chooseryear>
        </div>
    }
}

 

app/components/canlendar/chooseryear.js

import react from "react";
import classnames from "classnames";
export default class chooseryear extends react.component {
    constructor() {
        super();
    }
    //组件上树之后
    componentdidmount(){
        var self = this;
        //事件委托,因为td太多了
        $(this.refs.table).on("click","td", function(){
            //得到你点击的小格格里面的内容,内容就是年份
            var year = $(this).html();
            self.props.setyear(year);        //设年
            self.props.setview("date");     //回到日视图
        });
    }
 
    //显示表格
    showtable(){
        //算出基数年,比如当前2018年,基数年就是2010年。就是年份减去“零头”。
        const baseyear = this.props.year - this.props.year % 10;
        var arr = [];
        for(var i = 0; i < 10 ; i++){
            arr.push(
                <tr key={i}>
                    <td>{baseyear + i - 20}</td>
                    <td>{baseyear + i - 10}</td>
                    <td classname={classnames({"cur":baseyear + i == this.props.year})}>
              {baseyear + i}
            </td>
                    <td>{baseyear + i + 10}</td>
                    <td>{baseyear + i + 20}</td>
                </tr>
            )
        }
        return arr;
    }
    render() {
        return <div classname="chooseryear">
            <table ref="table">
                <tbody>
                    {this.showtable()}
                </tbody>
            </table>
        </div>
    }
}

css样式:

.canlendar .chooseryear table .cur{color:red;font-weight: bold;}
.canlendar .choosermonth table{
    width:100%;text-align: center;line-height: 40px;
}
.canlendar a{
    color: #2196f3;text-decoration: none;padding: 0 3px;
}

 

canlendar/canlendarmenu.js

import react from "react";
import pickerdate from "./pickerdate.js";
import pickeryear from "./pickeryear.js";
import chooserdate from "./chooserdate.js";
import chooseryear from "./chooseryear.js";
import choosermonth from "./choosermonth.js";
export default class canlendarmenu extends react.component {
    constructor() {
        super();
        this.state = {
            view : "date"  //当前的视图date、month、year
        }
    }
    //设置视图
    setview(view){
        this.setstate({view});
    }
    render() {
        //解构得到年、月、日
        const { year, month, date, setyear, setmonth, setdate, setshowmenu} = this.props;
         
        //定义chooser组件
        const chooser = ()=>{
            //根据state的view属性的值,来决定真实的chooser
            if(this.state.view == "date"){
                return <chooserdate
                    year={year}
                    month={month}
                    date={date}
                    setyear={setyear}
                    setmonth={setmonth}
                    setdate={setdate}
                    setshowmenu={setshowmenu}
                ></chooserdate>
            }else if(this.state.view == "year"){
                return <chooseryear
                    year={year}
                    setyear={setyear}
                    setview={this.setview.bind(this)}
                ></chooseryear>
            } else if (this.state.view == "month") {
                return <choosermonth
                    setmonth={setmonth}
                    setview={this.setview.bind(this)}
                ></choosermonth>
            }
        }

        //定义picker组件
        const picker = ()=>{
            if(this.state.view == "date"){
                return <pickerdate 
                    year={year} 
                    month={month} 
                    setyear={setyear} 
                    setmonth={setmonth} 
                    setview={this.setview.bind(this)}
                ></pickerdate> 
            }else if(this.state.view == "year"){
                return < pickeryear
                    year={year}
                    setyear={setyear}
                ></pickeryear >
            }else if(this.state.view == "month"){
                return null;
            }
        }

        return <div classname="canlendar_menu">
            <picker></picker>
            <chooser></chooser>
        </div>
    }
}

 

canlendar/pickeryear.js

import react from "react";
export default class pickeryear extends react.component {
    constructor() {
        super();
    }
    render() {
        const {year, setyear} = this.props;
        return <div classname="picker">
            <div classname="left">
                <a classname="btn" href="javascript:;" onclick={()=>{setyear(year-1)}}>
                   上1年
                </a>
            </div>
            <div classname="center">
                {year}年
            </div>
            <div classname="right">
                <a classname="btn" href="javascript:;" onclick={()=>{ setyear(year + 1)}}>
                    下1年
                </a>
            </div>
        </div>
    }
}

canlendar/choosermonth.js

import react from "react";
import classnames from "classnames";
export default class choosermonth extends react.component {
    constructor() {
        super();

    }
    componentdidmount(){
        //事件委托
        var self = this;
        $(this.refs.table).on("click","td", function(){
            self.props.setmonth(parseint($(this).data("m")));
            self.props.setview("date");
        })
    }
    render() {
        return <div classname="choosermonth">
            <table ref="table">
                <tbody>
                    <tr>
                        <td data-m="1">1月</td>
                        <td data-m="7">7月</td>
                    </tr>
                    <tr>
                        <td data-m="2">2月</td>
                        <td data-m="8">8月</td>
                    </tr>
                    <tr>
                        <td data-m="3">3月</td>
                        <td data-m="9">9月</td>
                    </tr>
                    <tr>
                        <td data-m="4">4月</td>
                        <td data-m="10">10月</td>
                    </tr>
                    <tr>
                        <td data-m="5">5月</td>
                        <td data-m="11">11月</td>
                    </tr>
                    <tr>
                        <td data-m="6">6月</td>
                        <td data-m="12">12月</td>
                    </tr>
                </tbody>
            </table>
        </div>
    }
}

 


 

上一篇:

下一篇: