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


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

一直在印象笔记写:

1:组件入门

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

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

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

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

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

ReactDOM.render(

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

document.getElementById('example')

);

等同于:

你好


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

ReactDOM.render(

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

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

document.getElementById('ex1')

);

等同于:

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

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

</span>
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-heading text-center">

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

</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,实际使用要先转译再使用!








React笔记





JSX转换插件













React Excel (单击列标题排序,双击单元格编辑,回车确认)
``` 暂时就这样啦。

文章作者: 2winter
文章链接: https://2winter.com
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 2winter !
  目录