React入门笔记:一个小表格组件的构建过程

版权声明:仅供参考,愿世界对我们温柔以待 https://blog.csdn.net/u010913414/article/details/82888624

vue,angular,react,这三个框架,本来打算学vue。图书馆资料就一本,就转向了React(图书馆突然买了好多。。。),其实还是因为它能够使用native开发,现在开发安卓我用的是kotlin,想着前端学习,也要加把劲了,迈入更好的路。

一直在印象笔记写:

1:组件入门

TIPS:引入库文件(现在还没到jsx,用了两个,一个核心,一个dom库)

<script src="react.js"></script>

<script src="react-dom.js"></script>

1.1使用预定义组件(这些是预定的组件构造器)

ReactDOM.render();//渲染函数

ReactDOM.render(“what”,where);//绑定用id

React.DOM.*({JSON属性},子节点}//属性省略null, 子节点可以嵌套,组件构造器

<div id="example"></div>

ReactDOM.render(

    React.DOM.h1(null,"你好,React"),

    document.getElementById('example')

);

等同于:<div><h1>你好</h1></div>

1.2:嵌套使用:(说实话,没用JSX时候,复杂的时候,我都写蒙了,找不到括号匹配了。。。)

ReactDOM.render(

    React.DOM.span({style:{color:"red"}},

        React.DOM.em({style:{color:"blue"}}," 我是斜体蓝色span"),"我是正常红色span"),

    document.getElementById('ex1')

    );

等同于:

<div id="ex1">

    <span style="color:"blue">我是斜体蓝色

        <em style="color:"red">我是正常红色</em>

    </span>

</div>

1.3.使用自定义组件(这个以后是主要使用的啦)

var myELe = React.createClass(

{

    propTypes:{

                name:React.PropTypes.string.isRequired,

                title:React.PropTypes.string

                    },

    getDefaultProps:function(){

                return {

                                title:"我是默认属性值"

                            }

        },

    render:function(){

                return React.DOM.span(null,"我是自定义组件span"+this.props.title)//调用属性值

    }

});//自定义组件函数

React.createClass();//参数,json格式,render渲染函数,返回React组件



ReactDOM.render(

    React.createElement(myEle),

    document.getElementById('ex3')

    );//引用



工厂模式:



    var myEle2 = React.createFactory(myEle);

    ReactDOM.render(

    myele2(),

    document.getElementById('ex3')

    );

tips:默认属性值,只能返回非isRequired的属性值,设置接收属性值的对象:propTypes:{属性名:属性值,React.PropTypes.值类型.是否必须

创建组件,渲染传入需要接收的属性值,如果非isRequired没有传,则使用getDefaultProps函数返回的值!

在定义组件对象时,this.props.属性名,可以调用属性

1.4 State状态(对象里面值为函数,称方法)

下面是一个完整的自定义组件与渲染

var myIput = React.createClass({

//默认属性json格式

    proptypes:{

        text:React.PropTypes.string

    },

//默认属性设置函数

    getDefaultProps:function(){

        return {

            text:''

        }

    },

//初始化状态函数,动态设置属性值

    getInitialState:function(){

        return {

            text:this.props.text

        }

    },

//自定义方法,设置state状态

    _textChange:function(e){

        this.setState({

            text:e.target.value

        })

    },

//渲染函数,设置监听器,onChange:自定义方法

    render:function(){

            return React.DOM.div(null,

                       React.DOM.textarea({

                           defaultValue : this.props.text,

                           onChange : this._textChange

                   }),

                  React.DOM.h3(null,this.state.text.length)

            )

        }

    

});//自定义组件,一个实时计算输入字符长度的组件



调用:

var myInput_render = ReactDOM.render(

    React.createElement(myIput,{text:'default'}),

    document.getElementById('ex4'));

1.5 外部访问组件

myInout_render.setState({text:""});//外部访问组件,并改变state,不推荐!

1.6 生命周期方法:使用生命周期给我们后来方面实时修改页面数据

componentWillUpdate()//组件再次渲染调用,如render前调用,组件的props与state发生改变会调用

componentDidUpdate()//render执行完毕,更新的组件同步DOM后调用,不会在初始化调用

componentWillMount()//新节点插入前调用

componentWillDidMount()//新节点插入之后调用

componentWillUnmount()//组件从DOM移除调用

shouldComponentUpdate(newProps,newState)//在componentWillUpdate之前触发

{···

_log:function(Mname,args){

        console.log(Mname,args);

    },

    componentWillUpdate:function(){

        this._log('componentWillUpdate:渲染前调用|props与state改变调用',arguments)

    },

    componentDidUpdate:function(){

        this._log('componentWillDidUpdate:render执行完,同步DOM之后调用',arguments)

    },

    shouldComponentUpdate:function(newProps,newState){

        this._log('shouldComponentUpdate:componentWillUpdate之前触发,返回false能禁止render调用',arguments);

        return true

    },

    componentDidMount:function(){

        this._log('componentDidMount:新节点插入之后触发',arguments)

    },

    componentWillMount:function(){

        this._log("componentWillMount:新节点插入之前触发",arguments)

    },

    componentWillUnmount:function(){

        this._log('componentWillUpdate:组件从DOM移触发',arguments)

    }

···}

1.6 mixin 简化重复的生命周期方法(其实就是一个json格式,简化了写法)

var myMixin_one = {

    _log:function(Mname,args){

        console.log(Mname,args);

    },

    componentWillUpdate:function(){

        this._log('componentWillUpdate:渲染前调用|props与state改变调用',arguments)

    },

    componentDidUpdate:function(){

        this._log('componentWillDidUpdate:render执行完,同步DOM之后调用',arguments)

    },

    shouldComponentUpdate:function(newProps,newState){

        this._log('shouldComponentUpdate:componentWillUpdate之前触发,返回false能禁止render调用',arguments);

        return true

    },

    componentDidMount:function(){

        this._log('componentDidMount:新节点插入之后触发',arguments)

    },

    componentWillMount:function(){

        this._log("componentWillMount:新节点插入之前触发",arguments)

    },

    componentWillUnmount:function(){

        this._log('componentWillUpdate:组件从DOM移触发',arguments)

    }

    

};

var myMixin_two = {

    proptypes:{

        text:React.PropTypes.string

    },

    getDefaultProps:function(){

        return {

            text:''

        }

    },

    getInitialState:function(){

        return {

            text:this.props.text

        }

    },

    _textChange:function(e){

        this.setState({

            text:e.target.value

        })

    },

};

var myIput = React.createClass({

    render:function(){

            return React.DOM.div(null,

                       React.DOM.textarea({

                           defaultValue:this.state.text,

                           onChange:this._textChange

                   }),

                  React.DOM.h3(null,this.state.text.length)

            )

        },



    mixins:[myMixin_one,myMixin_two]//用mixin替代周期函数与初始化方法

    

});

1.7 子组件:子组件从属于父组件

//定义父组件

var parCom = React.createClass({

    propTypes:{

        text:React.PropTypes.string

    },

    getDefaultProps:function(){

        return {

            text:''

        }

    },



    _textChange:function(e){

        this.setState({

            text:e.target.value

        })

    },

    getInitialState:function(){

        return {

            text:this.props.text

        }

    },

    render:function(){

        var counter = null;

        if(this.state.text.length>0){

//初始化子组件

            counter = React.DOM.h3(null,React.createElement(sonCom,{

                count:this.state.text.length

            }))

//父组件,渲染时候,检测条件,是否渲染子组件

//如果父组件的text属性值大于0,渲染子组件

        }

        return React.DOM.div(null,

            React.DOM.textarea({

            defaultValue:this.state.text,

            onChange:this._textChange

            }),counter//引用子组件

        )

    }

});

//定义子组件

var sonCom = React.createClass({

    name:'Counter',

    propTypes:{

        count:React.PropTypes.number.isRequired,

    },

    render:function(){

        return React.DOM.span(null,this.props.count);

    }

})

//调用

ReactDOM.render(React.createElement(parCom,{text:''}),document.getElementById('ex5'))

下面是一个完整的表格React应用demo过程部分代码来自:《React快速上手》

1.8 Excel组件

var Excel = React.createClass({

    displayName:'Excel',

    getInitialState:function(){

        return {

            data:this.props.initialdata

        }

    },

    render:function(){

        return React.DOM.table({className:"table"+" "+"table-bordered"},//多个类用拼接

                React.DOM.thead(null,

                    React.DOM.tr(null,

                        this.props.headers.map(function(title,idx){

//map()方法,将数组的值传入回调函数

// arr.map(function(currentValue,index,arr),thisValue) 

//参数说明 function(currentValue,index,arr) 必须,函数,数组中的每个元素都会执行这个函数函数参数 函数参数 currentValue 必须 当前元素值 index 可选 当前元素的索引值 arr 可选 当前元素属于的数组对象。

                            return React.DOM.th({key:idx},title);

                       })

                    )

                ),

                React.DOM.tbody(null,this.state.data.map(function(row,idx){

                    return React.DOM.tr({key:idx},

                        row.map(function(cell,idx){

                            return React.DOM.td({key:idx},cell)

                        })

                    )

                }))

            );

    }

});



var headers = ["book","author","lanage","sales"];

var data = [["math","jack","en","23"],["english","alice","23","en"]];



ReactDOM.render(React.createElement(Excel,{



    headers:headers,

    initialdata:data

}),document.getElementById('ex6'));

效果图:

实现排序:arr.sort(回调函数)

_sort:function(e){

        var column = e.target.cellIndex;//当前选中的列索引

        var data  = this.state.data.slice();//对数组的复制

        data.sort(function(a,b){

            console.log(a[column],b);

            return a[column]>b[column] ? 1: -1;

        });

        console.log(e.target.cellIndex);

//更新状态

        this.setState({

            data:data

        })

添加监听器:

React.DOM.thead({onClick:this._sort},

实现编辑:这里用了bootstrap的框架,很好看啊

getInitialState:function(){

        return {

            data:this.props.initialdata,

            edit:null

        };

    },

_edit:function(e){

        this.setState({

            edit:{

                row:parseInt(e.target.dataset.row,10),

                cell:e.target.cellIndex

            }

        });

    },

·····

    React.DOM.tbody({

                    onDoubleClick:this._edit},this.state.data.map(function(row,rowidx){

                    return React.DOM.tr({key:rowidx},

                        row.map(function(cell,idx){

                            var content = cell;

                            var edit = this.state.edit;

                            if(edit && edit.row === rowidx && edit.cell === idx){

                                content = React.DOM.form({

                                    onSubmit:this._save

                                },React.DOM.input({

                                    type:"text",

                                    className:"form-control",

                                    defaultValue:content

                                }))

                            }

                            return React.DOM.td({key:idx,"data-row":rowidx},content)

                        },this)

                    )

                },this))

效果图:

实现保存:回车保存

_save:function(e){

        e.preventDefault();//阻止默认事件,防止重新加载

        var input = e.target.firstChild;//引用输入框值

        var data = this.state.data.slice();//复制一份数据修改

        data[this.state.edit.row][this.state.edit.cell] = input.value;//修改指定行指定cell数据

        this.setState({

            data:data,//刷新数据

            edit:null//去除input

        })



    },

效果图:

完整源代码:有注释可以研究一下!

<div class="panel panel-primary">

    <div class="panel-heading text-center">

        React Excel (单击列标题排序,双击单元格编辑,回车确认)

    </div>

<div id="ex6" class="panel-body"></div>

</div>



//定义表格组件

var Excel = React.createClass({

    displayName:'Excel',//内部为React标记此组件名

    getInitialState:function(){

        return {

            data:this.props.initialdata,//初始化数据

            edit:null//是否开启编辑

        };

    },

//排序方法

    _sort:function(e){

        var column = e.target.cellIndex;//获取列索引

        var data  = this.state.data.slice();//复制数组

//数组排序方法,传入,回调函数(比较两个数据,返回真假)

        data.sort(function(a,b){

            console.log(a[column],b);

            return a[column]>b[column] ? 1: -1;

        });//每次排序后,刷新状态

        console.log(e.target.cellIndex);

        this.setState({

            data:data

        })

    },

//编辑方法

    _edit:function(e){

        this.setState({

            edit:{

                row:parseInt(e.target.dataset.row,10),//强制转整形,通过自定义的dataset-row

                cell:e.target.cellIndex//获取row与cell即每个单元格的定位

            }

        });

    },

//提交保存

    _save:function(e){

        e.preventDefault();//阻止浏览器默认事件

        var input = e.target.firstChild;//获取输入框值

        var data = this.state.data.slice();

        data[this.state.edit.row][this.state.edit.cell] = input.value;//修改指定单元格数据

        this.setState({

            data:data,

            edit:null//去除输入框

        })



    },

    render:function(){

        return React.DOM.table({className:"table"+" "+"table-bordered"},

                React.DOM.thead({

                        onClick:this._sort},//添加单击监听器

                    React.DOM.tr(null,

                        this.props.headers.map(function(title,idx){

                            return React.DOM.th({key:idx},title);

                       })

                    )

                ),

                React.DOM.tbody({//添加双击监听器

                    onDoubleClick:this._edit},this.state.data.map(function(row,rowidx){

                    return React.DOM.tr({key:rowidx},

                        row.map(function(cell,idx){

                            var content = cell;

                            var edit = this.state.edit;//获取edit数据,判断覆盖单元格并生成input的定位

                            if(edit && edit.row === rowidx && edit.cell === idx){

                                content = React.DOM.form({

                                    onSubmit:this._save//表单事件

                                },React.DOM.input({

                                    type:"text",

                                    className:"form-control",

                                    style:{

                                        maxWidth:"100px"

                                    },

                                    defaultValue:content

                                }))

                            }

                            return React.DOM.td({key:idx,"data-row":rowidx},content)

                        },this)

                    )

                },this))

            );

    }

});



var headers = ["图书","作者","语言","售价"];

var data = [["数学书","李","中文","23元"],["英语书","爱丽丝","英文","26元"],["PHP编程","鲍勃","英文","21元"],["React笔记","bore","中文","26元"]];



ReactDOM.render(React.createElement(Excel,{



    headers:headers,

    initialdata:data

}),document.getElementById('ex6'));

现在用JSX简化表格组件

1.9 JSX实现Excel组件:JSX在学习时候,引入browser.js来转译jsx到js,实际使用要先转译再使用!

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8" />

<title>React笔记</title>

<script src="react.js"></script>

<script src="react-dom.js"></script>

<script src="browser.min.js"></script>JSX转换插件

<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.js"></script>

<script src="https://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>

<link href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">

<style type="text/css">



.border{

    border: 1px solid red;margin: 10px;padding: 10px;

}

.borderIn{

    border: 1px solid blue;margin: 10px;padding: 10px;

}



</style>

</head>

<body>

<div class="panel panel-primary">

    <div class="panel-heading text-center">

        React Excel (单击列标题排序,双击单元格编辑,回车确认)

    </div>

<div id="ex6" class="panel-body"></div>

</div>



<script type="text/babel">



var Excel = React.createClass(

{    

    /*定义内部组件名字*/

    displayName:'Excel',

    /*定义接收属性*/

    propTypes:{

        headers:React.PropTypes.arrayOf(React.PropTypes.string),/*初始化头部,接收数组,数组值为string*/

        initialdata:React.PropTypes.arrayOf(React.PropTypes.arrayOf(React.PropTypes.string))

        },/*初始化内容,数据接收数组,值为string*/

        /*初始化属性*/

    getInitialState:function(){

        return {

            data:this.props.initialdata,/*初始化组件内部属性属性值*/

            sortby:null,/*排序*/

            edit:null,/*编辑*/

            search:false,/*搜索*/

            desc:false

        };

    },

    /*排序方法*/

    _sort:function(e) {

        var cloumn = e.target.cellIndex;/*获取触发所在的列索引*/

        console.log(e.target.cellIndex);

        var data = this.state.data.slice();/*复制数据操作*/

        var desc = this.state.desc;

        data.sort(function(a,b) {

            console.log(a);

            console.log(b);

            return desc ? (a[cloumn]>b[cloumn] ? 1 : -1) : (a[cloumn]<b[cloumn] ? 1 : -1);/*判断排序*/

        });

        /*更新状态*/

        if(desc == false){

            desc = true;

        }else{

            desc = false;

        }

        this.setState({

            data:data,

            desc:desc

        });

    },

    /*编辑方法*/

    _edit:function(e){

        this.setState({

            edit:{

                row:parseInt(e.target.dataset.row,10),

                cell:e.target.cellIndex,

            }

        });/*刷新状态:定位点击单元格位置*/

    },

    /*保存方法*/

    _save:function(e){

        e.preventDefault();/*阻止默认网页重载*/

        var input = e.target.firstChild;/*获取单元格文本*/

        var data = this.state.data.slice();/*复制数据*/

        data[this.state.edit.row][this.state.edit.cell] = input.value;/*将单元格文本存储到指定data位置*/

        this.setState({

            data:data,

            edit:null,});

    },

    _json:function(){



    },

    _csv:function(){



    },

    _search:function(){



    },

    /*渲染工具栏*/    

    render_head:function(){

        return (

            <div className="container-fluid">

                <div className="row">

                    <div className="col-xs-2" >

                        <button type="button" onClick={this._search}  style={{margin:"5px",width:"100%"}} className="btn btn-primary" >搜索</button>

                    </div>

                    <div className="col-xs-2">

                        <button type="button" onClick={this._json} style={{margin:"5px",width:"100%"}} className="btn btn-default">导出JSON</button>

                    </div>

                    <div className="col-xs-2">

                        <button type="button"onClick={this._csv} style={{margin:"5px",width:"100%"}} className="btn btn-success">导出CSV</button>

                    </div>

                </div>

            </div>

            )



    },

    /*渲染表格*/

    render:function(){

        return     (/*这个括号不可以换行。。。*/

            <div>/*不乐意返回多个顶级节点,用div包裹*/

                {this.render_head()}

                <table className="table table-bordered">

                <thead onClick={this._sort}>

                    <tr>{

                        /*在{}中编写JS*/

                        this.props.headers.map(function(title,idx){

                            return <th key={idx}>{title+=this.state.desc ? '\u2193' : '\u2191'}</th>;



                        },this)

                        }

                    </tr>

                </thead>

                <tbody onDoubleClick={this._edit}>

                    {

                        this.state.data.map(function(row,rowidx){

                            return (

                                <tr key={rowidx}>

                                    {

                                        row.map(function(cell,idx){

                                            var content = cell;

                                            var edit = this.state.edit;

                                            if(edit && edit.row === rowidx && edit.cell === idx){

                                                content = (

                                                    <form onSubmit={this._save}>

                                                        <input style={{maxWidth:"100px"}} type="text" className="form-control" defaultValue={cell} />

                                                    </form>);

                                            }

                                            return <td key={idx} data-row={rowidx}>{content}</td>

                                        },this)

                                    }

                                </tr>

                            );

                        },this)

                    }

                </tbody>

            </table>

            </div>

            );

        

    },



    }

);



var headers = ["图书","作者","语言","售价"];

var data = [["数学书","李","中文","23元"],

["英语书","爱丽丝","英文","26元"],

["PHP编程","鲍勃","英文","21元"],

["React笔记","bore","中文","26元"]];



ReactDOM.render(React.createElement(Excel,{



    headers:headers,

    initialdata:data

}),document.getElementById('ex6'));





</script>

</body>

</html>

暂时就这样啦。

猜你喜欢

转载自blog.csdn.net/u010913414/article/details/82888624