React入门笔记:一个小表格组件的构建过程
React入门笔记:一个小表格组件的构建过程
❄️2wintervue,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>
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,实际使用要先转译再使用!
<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>```
暂时就这样啦。