CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准。C系列认证历经近一年的实际线下调研、考察、迭代、测试,并梳理出软件工程师开发过程中所需的各项技术技能,结合企业招聘需求和人才应聘痛点,基于公开、透明、公正的原则,甑别人才时确保真实业务场景、全部上机实操、所有过程留痕、存档不可篡改。

我们每天将都会精选CSDN站内技术文章供大家学习,帮助大家系统化学习IT技术。

学习React不是一蹴而就的事情,入门似乎也没那么简单。但一切都是值得的。

今天给大家带来一个详细的React的实例,实例并不难,但对于初学者而言,足够认清React的思考和编写过程。认真完成这个实例的每一个细节会让你受益匪浅。接下来我们开始吧!

代码下载

预览
首先说明一下,本例究竟做了什么。本文实现了一个单页面人员管理系统的前台应用。包括以下功能:

  • 人员基本信息列表;
  • 人员的录入及删除;
  • 人员详细信息的查看;
  • 人员信息的编辑;
  • 根据人员身份进行筛选;
  • 根据人员某些属性进行排序;
  • 根据人姓名、年龄、身份、性别等关键字进行人员搜索。

第一步:划分UI Component
React is all about modular, composable components.

React是模块化、组件化的。我们这里第一步要做的就是将应用划分成各个组件。我在图一、图二的基础上圈出了我们即将实现的各个组件。

每个圈出的组件功能如下,这是本应用的框架,请大家务必看清楚,其中斜体字是各个组件的名称:

ManageSystem 图三最外层的红色方框,这是管理模块的最外层容器,容纳整个应用;
StaffHeader 图三最上层蓝色方框,该模块接收用户操作的输入,包括关键字搜索输入、筛选条件以及排序方式;
StaffItemPanel 图三中间蓝色方框,该模块用于展示所有基于用户操作(关键字搜索、筛选、排序)结果的条目;
StaffFooter 图三最下层蓝色方框,该模块用于新人员的添加;
StaffItem 图三内层的红色方框,该模块用于展示一条人员的基本信息,包括删除和详情操作的按钮;
StaffDetail 图四的红色方框,每当点击StaffItem的’详情’后会显示该条目的详细信息。该模块用于展示人员的详细信息,兼有人员信息编辑的功能。
为了更清楚地展示框架结构:

ManageSystemStaffHeaderStaffItemPanelStaffItemStaffItemStaffItem...StaffFooterStaffDetail(只在点击某条目的详情后展示)

第二步:构建静态版的React应用
在第一步中我们已经划分了各个组件,也说明了各个组件的职责。接下来我们分步完成我们的应用,首先我们做一个静态版的React,只用于render UI组件,但并不包含任何交互。

这个步骤我们只需要参照图一、图二去做就好了,绝大部分工作基本上就是使用JSX按部就班地写html代码。这个过程不需要太多思考。每个组件中都仅仅只包含一个render()方法。

需要注意的是,静态版的应用,数据由父组件通过props属性向下传递,state属性是用不到的,记住,state仅仅为动态交互而生。

本应用的组件相对较多,我们不妨采用bottom-up的方式,从子组件开始。

好了,我们开始吧。

StaffHeader
首先以StaffHeader为例,创建一个StaffHeader.js文件。如下:


import React from 'react';
export default class StaffHeader extends React.Component{render(){return (<div><h3 style={{'text-align':'center'}}>人员管理系统</h3><table className="optHeader"><tbody><tr><td className="headerTd"><input type='text' placeholder='Search...' /></td><td className="headerTd"><label for='idSelect'>人员筛选</label><select id='idSelect'><option value='0'>全部</option><option value='1'>主任</option><option value='2'>老师</option><option value='3'>学生</option><option value='4'>实习</option></select></td><td><label for='orderSelect'>排列方式</label><select id='orderSelect'><option value='0'>身份</option><option value='1'>年龄升</option><option value='2'>年龄降</option></select></td></tr></tbody></table></div>);}
}

该组件主要用于提供搜索框,人员筛选下拉框以及排列方式下拉框。没错,我们首先就是要搭建一个静态版的React。呈现的样子参考图三最上方的蓝色框。当然,为了实现最终的样式,需要css的配合,css不是本文的关注点,本应用的css也十分简单,自行查看源代码。

StaffItem
StaffItem是每个具体人员的基本信息组件,用于展示人员的基本信息并接收用户的删除和点击详情的操作。新建一个StaffItem.js(该组件在StaffItemPanel中被引用):


import React from 'react';
export default class StaffItem extends React.Component{render(){return (<trstyle={{'cursor': 'pointer'}}><td className='itemTd'>{this.props.item.info.name}</td><td className='itemTd'>{this.props.item.info.age}</td><td className='itemTd'>{this.props.item.info.id}</td><td className='itemTd'>{this.props.item.info.sex}</td><td className='itemTd'><a className="itemBtn">删除</a><a className="itemBtn">详情</a></td></tr>);}
}

StaffItemPanel
接下来是StaffItemPanel,该组件仅用于展示由父组件传入的各个人员条目,新建一个StaffItemPanel.js文件:


import React from 'react';
import StaffItem from './StaffItem.js';
export default class StaffItemPanel extends React.Component{render(){let items = [];if(this.props.items.length == 0) {items.push(<tr><th colSpan="5" className="tempEmpty">暂无用户</th></tr>);}else {this.props.items.forEach(item => {items.push(<StaffItem key={item.key} item={item}/>);});}return (<table className='itemPanel'><thead><th className='itemTd'>姓名</th><th className='itemTd'>年龄</th><th className='itemTd'>身份</th><th className='itemTd'>性别</th><th className='itemTd'>操作</th></thead><tbody>{items}</tbody></table>);}
}

该组件的功能相对简单,其中

if(this.props.items.length == 0) {items.push(<tr><th colSpan="5" className="tempEmpty">暂无用户</th></tr>);}else {this.props.items.forEach(item => {items.push(<StaffItem key={item.key} item={item} />);});}

是为了在暂无条目的时候给出相应的提示,如下图:

图5

StaffFooter
StaffFooter组件的功能是添加新人员,新建StaffFooter.js文件:


import React from 'react';
export default class StaffFooter extends React.Component{render(){return (<div><h4 style={{'text-align':'center'}}>人员新增</h4><hr/><form ref='addForm' className="addForm"><div><label for='staffAddName' style={{'display': 'block'}}>姓名</label><input ref='addName' id='staffAddName' type='text' placeholder='Your Name'/></div><div><label for='staffAddAge' style={{'display': 'block'}}>年龄</label><input ref='addAge' id='staffAddAge' type='text' placeholder='Your Age(0-150)'/></div><div><label for='staffAddSex' style={{'display': 'block'}}>性别</label><select ref='addSex' id='staffAddSex'><option value='男'>男</option><option value='女'>女</option></select></div><div><label for='staffAddId' style={{'display': 'block'}}>身份</label><select ref='addId' id='staffAddId'><option value='主任'>主任</option><option value='老师'>老师</option><option value='学生'>学生</option><option value='实习'>实习</option></select></div><div><label for='staffAddDescrip' style={{'display': 'block'}}>个人描述</label><textarea ref='addDescrip' id='staffAddDescrip' type='text'></textarea></div><p ref="tips" className='tips' >提交成功</p><p ref='tipsUnDone' className='tips'>请录入完整的人员信息</p><p ref='tipsUnAge' className='tips'>请录入正确的年龄</p><div><button>提交</button></div></form></div>)}
}

代码看起来比较长,其实就是一个html表单,这个步骤基本都是不需要太多思考的操作,代码也没有任何理解上的难度,记住,我们现在就是要把整个框架搭起来,做一个静态版的应用!同样的,呈现出最终的样式,需要一些css,自行参考源代码。呈现的样子见图三最下面的蓝色方框。

StaffDetail
通常情况下,该组件是不显示的,只有当用户点击某条目的详情的时候,我用了一种动画效果将该组件’浮现出来’。方法就是在css中将该组件的z-index设置为一个很大的值,比如100,然后通过逐渐改变背景透明度的动画实现浮现的效果。目前我们只需要做一个静态版的React,尚未实现用户点击操作的交互,所以这里只需要创建以下js文件,并在css中将.overLay的display设置为none就可以了,源码中的css文件已经做好了。


import React from 'react';
export default class StaffDetail extends React.Component{render(){let staffDetail = this.props.staffDetail;  if(!staffDetail)return null;return (<div className="overLay"><h4 style={{'text-align':'center'}}>点击'完成'保存修改,点击'关闭'放弃未保存修改并退出.</h4><hr/><table ref="editTabel"><tbody><tr><th>姓名</th><td><input id='staffEditName' type="text" defaultValue={staffDetail.info.name}></input></td></tr><tr><th>年龄</th><td><input id='staffEditAge' type="text" defaultValue={staffDetail.info.age}></input></td></tr><tr><th>性别</th><td><select ref='selSex' id='staffEditSex'><option value="男">男</option><option value="女">女</option></select></td></tr><tr><th>身份</th><td><select ref="selId" id='staffEditId'><option value="主任">主任</option><option value="老师">老师</option><option value="学生">学生</option><option value="实习">实习</option></select></td></tr><tr><th>个人描述</th><td><textarea id='staffEditDescrip' type="text" defaultValue={staffDetail.info.descrip}></textarea></td></tr></tbody></table><p ref='Dtips' className='tips'>修改成功</p><p ref='DtipsUnDone' className='tips'>请录入完整的人员信息</p><p ref='DtipsUnAge' className='tips'>请录入正确的年龄</p><button>完成</button><button>关闭</button></div>);}
}

和staffFooter类似,这里主要就是一个表单。

ManageSystem
子组件都已经做好了,接下来就是最外层的容器了。按部就班,新建一个ManageSystem.js:


import React from 'react';
import StaffHeader from './StaffHeader.js';
import StaffItemPanel from './StaffItemPanel.js';
import StaffFooter from './StaffFooter.js';
import StaffDetail from './StaffDetail.js';var rawData = [{ info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 20, name: '张三', id: '主任'}},{ info: {descrip:'我是一匹来自远方的狼。', sex: '女', age: 21, name: '赵静', id: '学生'}},{ info: {descrip:'我是一匹来自远方的狼。', sex: '女', age: 22, name: '王二麻', id: '学生'}},{ info: {descrip:'我是一匹来自远方的狼。', sex: '女', age: 24, name: '李晓婷', id: '实习'}},{ info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 23, name: '张春田', id: '实习'}},{ info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 22, name: '刘建国', id: '学生'}},{ info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 24, name: '张八', id: '主任'}},{ info: {descrip:'我是一匹来自远方的狗。', sex: '男', age: 35, name: '李四', id: '老师'}},{ info: {descrip:'我是一匹来自远方的猪。', sex: '男', age: 42, name: '王五', id: '学生'}},{ info: {descrip:'我是一匹来自远方的牛。', sex: '男', age: 50, name: '赵六', id: '实习'}},{ info: {descrip:'我是一匹来自远方的马。', sex: '男', age: 60, name: '孙七', id: '实习'}}];class App extends React.Component {render(){return (<div><StaffHeader/><StaffItemPanel items={rawData} /><StaffFooter/><StaffDetail/></div>);}
}React.render(<App />, document.getElementById('app'));

以上代码中rawData是演示数据,生产中的数据应该从数据库获得,这里为了简便,直接生成了11条演示用的数据。

第三步:编译并打包
在第二步中,我们已经生成了各个component以及subcomponent。主要的任务已经完成了,这一步是做什么的呢?

简单地说,上文中我们编写React Component的过程中,使用了es6和JSX的语法。(特别值得一提的是es6的Module,终于从语言规格上让Javascript拥有了模块功能。如今js渐入佳境,学习es6是十分重要且值得的!)但这些目前是不能被浏览器直接支持的。所以在使用之前,要先经过’编译’,这个过程我们是使用Babel完成的。

关于Babel,正如其官网所言–Babel is a Javascript compiler.本应用中,它帮我们完成了es6以及JSX的编译。只不过在本例中babel是以webpack的loader的方式出现的。

关于webpack这里也不多言了–webpack is a module bundler.请大家自己查阅相关资料。

安装依赖项
在这里,首先执行以下命令,安装开发依赖:

npm install

该命令会自动读取当前目录下的package.json文件,并自行安装其中的依赖项。文件内容如下:

{"name": "StaffManage","version": "1.0.0","description": "","main": "","scripts": {"start": "webpack"},"author": "WYH","license": "ISC","devDependencies": {"babel-core": "^6.14.0","babel-loader": "^6.2.5","babel-preset-es2015": "^6.14.0","babel-preset-react": "^6.11.1","webpack": "^1.13.2"}
}

更具体地说,其中的开发依赖项就是

  "devDependencies": {"babel-core": "^6.14.0","babel-loader": "^6.2.5","babel-preset-es2015": "^6.14.0","babel-preset-react": "^6.11.1","webpack": "^1.13.2"}

编译打包
安装开发依赖项后,接下来就是使用webpack打包了,webpack的loader在解析文件的时候会自动使用babel对文件进行编译。配置文件如下:

module.exports = {entry: __dirname + '/src/ManageSystem.js',output: {path: __dirname + '/build',filename: "bundle.js"},externals: {'react': 'React'},devtool: 'eval-source-map',  //生成source filemodule: {loaders: [{test: /\.js$/,exclude: /node_modules/,loader: 'babel',query: {presets: ['es2015', 'react']}}]}
};

将第二步中的所有组件都放到当前目录下的src目录中,目录结构可以参考源代码,然后执行以下命令:

npm start

该命令也是在package.json中指定的。

"scripts": {"start": "webpack"
}

好了,在build目录下应该已经生成bundle.js文件,这就是我们打包好的文件,我们只需要在html中引用它就行了。

在当前目录下生成html文件如下:

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8"><title>人员管理</title><link href="build/style.css" rel="stylesheet" /></head><body><div id="app"></div><script src="http://cdn.bootcss.com/react/0.13.3/react.min.js"></script><script src="build/bundle.js"></script></body>
</html>

接下来在浏览器中打开index.html看看吧,静态版的React已经生成了,只是还没有动态交互而已。至此,已经完成了构建静态版的React的工作,大框架已经建立,接下来我们让它动起来!

第四步:添加STAFF类
本文应用涉及的功能有排序,筛选、新增、删除、修改以及关键字搜索等。功能较多,业务逻辑有些复杂。为了让React集中精力完成view层的事情,我们这里新建一个STAFF类来完成业务逻辑。

Javascript中,类的实现是基于其原型继承机制的。但在es6中,提供了更接近传统面向对象语言的写法,引入了类(class)的概念。我们可以通过class关键字来定义类。实际上,es6的class只是一个语法糖(syntax sugar),它的绝大部分功能,es5均可以做到。而引入的class写法,是为了让对象的写法更加清晰、更加具有面向对象的感觉。

接下来我们新建一个STAFF.js文件:


class staffItem {constructor(item){this.info = {};this.info.name = item.name;this.info.age = item.age || 0;this.info.sex = item.sex;this.info.id = item.id;this.info.descrip = item.descrip || '';this.key = ++staffItem.key;}
}
staffItem.key = 0;export default class STAFF {constructor(){this.allStaff = [new staffItem(STAFF.rawData[0]),new staffItem(STAFF.rawData[1]),new staffItem(STAFF.rawData[2]),new staffItem(STAFF.rawData[3]),new staffItem(STAFF.rawData[4]),new staffItem(STAFF.rawData[5]),new staffItem(STAFF.rawData[6]),new staffItem(STAFF.rawData[7]),new staffItem(STAFF.rawData[8]),new staffItem(STAFF.rawData[9]),new staffItem(STAFF.rawData[10])];this.staff = this.allStaff;}
}STAFF.rawData = [{ descrip:'我是一匹来自远方的狼。', sex: '男', age: 20, name: '张三', id: '主任'},{ descrip:'我是一匹来自远方的狼。', sex: '女', age: 21, name: '赵静', id: '学生'},{ descrip:'我是一匹来自远方的狼。', sex: '女', age: 22, name: '王二麻', id: '学生'},{ descrip:'我是一匹来自远方的狼。', sex: '女', age: 24, name: '李晓婷', id: '实习'},{ descrip:'我是一匹来自远方的狼。', sex: '男', age: 23, name: '张春田', id: '实习'},{ descrip:'我是一匹来自远方的狼。', sex: '男', age: 22, name: '刘建国', id: '学生'},{ descrip:'我是一匹来自远方的狼。', sex: '男', age: 24, name: '张八', id: '主任'},{ descrip:'我是一匹来自远方的狗。', sex: '男', age: 35, name: '李四', id: '老师'},{ descrip:'我是一匹来自远方的猪。', sex: '男', age: 42, name: '王五', id: '学生'},{ descrip:'我是一匹来自远方的牛。', sex: '男', age: 50, name: '赵六', id: '实习'},{ descrip:'我是一匹来自远方的马。', sex: '男', age: 60, name: '孙七', id: '实习'}];

在STAFF.js中我们实际上创建了2个类,为了实现更好的’封装性’,我们将每一个人员条目单独作为一个staffItem类,该对象中包含了该人员的所有信息,在本应用中包含他的姓名、年龄、性别、身份、个人描述等,实践中我们可以加入类似入职时间,福利薪酬,个人经历等信息。另外还有一个key值,它是一个类变量,这个值是唯一标识该staffItem用的。

在第二步,我们在ManageSystem.js中伪造了一些数据,现在我们也把它搬到STAFF中。毕竟React不是存数据用的。

在STAFF类的构造函数中,创建了2个实例变量,一个是allStaff,其中存储所有staffItem;一个是staff,它是最终需要给React展示的数据,是经过用户筛选操作、关键字搜索操作之后得到的人员数组。之所以这么设计变量也是为了后面的筛选、搜索等功能。在这里我们尚无这些操作的逻辑,直接将allStaff赋给staff即可。

好了,接下来在ManageSystem中引入Staff.js,并初始化state:


import React from 'react';
import StaffHeader from './StaffHeader.js';
import StaffItemPanel from './StaffItemPanel.js';
import StaffFooter from './StaffFooter.js';
import StaffDetail from './StaffDetail.js';import STAFF from './STAFF.js';class App extends React.Component {constructor(){super();this.state = {staff : new Staff};}render(){return (<div><StaffHeader/><StaffItemPanel items={this.state.staff.staff} /><StaffFooter/><StaffDetail/></div>);}
}React.render(<App />, document.getElementById('app'));    

在构造函数中,new了一个STAFF类,然后将this.state.staff.staff传入<StaffItemPanel/>的items属性。

然后重新编译打包:

npm start

再次在浏览器打开index.html文件,虽然还是一个静态版的React,不过它已经变得更加模块化和’专一’了,结构也更加漂亮。

第五步:完成新增人员功能
关于state
上文说过,state是为交互而生的。React是自上而下的单向数据流,state通常由上层组件拥有并控制,state的变化将触发建立在该state上的一系列自上而下的组件更新。注意,组件只能update它自己的state,如果下层组件的操作希望改变应用的状态,形成一个inverse data flow–反向数据流,我们需要从上层组件传入一个回调函数。关于state如何确定,可以参考官网一篇文章Thinking in React。接下来我们看人员功能添加是如何完成的。

实现人员新增功能
真正让React动起来,不妨从新增人员逻辑开始吧,这个功能比较纯粹,和其他业务耦合度不高。重新打开StaffFooter.js,加入部分代码:


import React from 'react';
export default class StaffFooter extends React.Component{handlerAddClick(evt){evt.preventDefault();let item = {};let addForm = React.findDOMNode(this.refs.addForm);let sex = addForm.querySelector('#staffAddSex');let id = addForm.querySelector('#staffAddId');item.name = addForm.querySelector('#staffAddName').value.trim();item.age = addForm.querySelector('#staffAddAge').value.trim();item.descrip = addForm.querySelector('#staffAddDescrip').value.trim();item.sex = sex.options[sex.selectedIndex].value;item.id = id.options[id.selectedIndex].value;/**表单验证*/if(item.name=='' || item.age=='' || item.descrip=='') {let tips = React.findDOMNode(this.refs.tipsUnDone);tips.style.display = 'block';setTimeout(function(){tips.style.display = 'none';}, 1000);return;}//非负整数let numReg = /^\d+$/;if(!numReg.test(item.age) || parseInt(item.age)>150) {let tips = React.findDOMNode(this.refs.tipsUnAge);tips.style.display = 'block';setTimeout(function(){tips.style.display = 'none';}, 1000);return;}this.props.addStaffItem(item);addForm.reset();//此处应在返回添加成功信息后确认let tips = React.findDOMNode(this.refs.tips);tips.style.display = 'block';setTimeout(function(){tips.style.display = 'none';}, 1000);}render(){return (<div><h4 style={{'text-align':'center'}}>人员新增</h4><hr/><form ref='addForm' className="addForm"><div><label for='staffAddName' style={{'display': 'block'}}>姓名</label><input ref='addName' id='staffAddName' type='text' placeholder='Your Name'/></div><div><label for='staffAddAge' style={{'display': 'block'}}>年龄</label><input ref='addAge' id='staffAddAge' type='text' placeholder='Your Age(0-150)'/></div><div><label for='staffAddSex' style={{'display': 'block'}}>性别</label><select ref='addSex' id='staffAddSex'><option value='男'>男</option><option value='女'>女</option></select></div><div><label for='staffAddId' style={{'display': 'block'}}>身份</label><select ref='addId' id='staffAddId'><option value='主任'>主任</option><option value='老师'>老师</option><option value='学生'>学生</option><option value='实习'>实习</option></select></div><div><label for='staffAddDescrip' style={{'display': 'block'}}>个人描述</label><textarea ref='addDescrip' id='staffAddDescrip' type='text'></textarea></div><p ref="tips" className='tips' >提交成功</p><p ref='tipsUnDone' className='tips'>请录入完整的人员信息</p><p ref='tipsUnAge' className='tips'>请录入正确的年龄</p><div><button onClick={this.handlerAddClick.bind(this)}>提交</button></div></form></div>)}
}

我们在提交的按钮上绑定了点击事件。点击提交按钮后,执行以下函数:

handlerAddClick(evt){evt.preventDefault();let item = {};let addForm = React.findDOMNode(this.refs.addForm);let sex = addForm.querySelector('#staffAddSex');let id = addForm.querySelector('#staffAddId');item.name = addForm.querySelector('#staffAddName').value.trim();item.age = addForm.querySelector('#staffAddAge').value.trim();item.descrip = addForm.querySelector('#staffAddDescrip').value.trim();item.sex = sex.options[sex.selectedIndex].value;item.id = id.options[id.selectedIndex].value;/**表单验证*/if(item.name=='' || item.age=='' || item.descrip=='') {let tips = React.findDOMNode(this.refs.tipsUnDone);tips.style.display = 'block';setTimeout(function(){tips.style.display = 'none';}, 1000);return;}//非负整数let numReg = /^\d+$/;if(!numReg.test(item.age) || parseInt(item.age)>150) {let tips = React.findDOMNode(this.refs.tipsUnAge);tips.style.display = 'block';setTimeout(function(){tips.style.display = 'none';}, 1000);return;}this.props.addStaffItem(item);addForm.reset();//此处应在返回添加成功信息后确认let tips = React.findDOMNode(this.refs.tips);tips.style.display = 'block';setTimeout(function(){tips.style.display = 'none';}, 1000);
}

这里我们获取并简单处理了表单,特别注意

this.props.addStaffItem(item);

这一行代码,就是调用了ManageSystem通过prop属性传入的回调函数。在ManageSystem中加入相关代码:


import React from 'react';
import StaffHeader from './StaffHeader.js';
import StaffItemPanel from './StaffItemPanel.js';
import StaffFooter from './StaffFooter.js';
import StaffDetail from './StaffDetail.js';import Staff from './STAFF.js';class App extends React.Component {constructor(){super();this.state = {staff : new Staff,staffDetail: null};}//增addStaffItem(item){this.setState({staff: this.state.staff.addStaffItem(item)});}render(){return (<div><StaffHeader/><StaffItemPanel items={this.state.staff.staff}}/><StaffFooter addStaffItem={this.addStaffItem.bind(this)}/><StaffDetail/></div>);}
}React.render(<App />, document.getElementById('app'));

在<StaffFooter addStaffItem={this.addStaffItem.bind(this)}/>中传入了addStaffItem方法。

//增
addStaffItem(item){this.setState({staff: this.state.staff.addStaffItem(item)});
}

中更新了自己的state。只不过具体的逻辑是在STAFF类的方法中完成的。

STAFF.js:


export default class STAFF {constructor(){this.allStaff = [new staffItem(STAFF.rawData[0]),new staffItem(STAFF.rawData[1]),new staffItem(STAFF.rawData[2]),new staffItem(STAFF.rawData[3]),new staffItem(STAFF.rawData[4]),new staffItem(STAFF.rawData[5]),new staffItem(STAFF.rawData[6]),new staffItem(STAFF.rawData[7]),new staffItem(STAFF.rawData[8]),new staffItem(STAFF.rawData[9]),new staffItem(STAFF.rawData[10])];this.staff = this.allStaff;}//增addStaffItem(item) {let newItem = new staffItem(item);this.allStaff.push(newItem);this.staff = this.allStaff;return this;}
}

重新编译打包生成bundle.js文件:

npm start

再次在浏览器中打开index.html文件,试试我们新添加的人员添加功能吧!

第六步:完成关键字搜索功能
类似第五步新人员的添加,我们首先给StaffHeader中的搜索输入框绑定一个onChange事件,每当搜索内容改变时,触发该函数:

StaffHeader.js


import React from 'react';
export default class StaffHeader extends React.Component{//searchhandlerSearch(){let bar = React.findDOMNode(this.refs.searchBar);let value = bar.value;this.props.searchStaff(value);}render(){return (<div><h3 style={{'text-align':'center'}}>人员管理系统</h3><table className="optHeader"><tbody><tr><td className="headerTd"><input ref='searchBar' onChange={this.handlerSearch.bind(this)} type='text' placeholder='Search...' /></td><td className="headerTd"><label for='idSelect'>人员筛选</label><select id='idSelect'><option value='0'>全部</option><option value='1'>主任</option><option value='2'>老师</option><option value='3'>学生</option><option value='4'>实习</option></select></td><td><label for='orderSelect'>排列方式</label><select id='orderSelect'><option value='0'>身份</option><option value='1'>年龄升</option><option value='2'>年龄降</option></select></td></tr></tbody></table></div>);}
}

同样在事件处理函数中,调用了通过props属性传入的回调函数searchStaff:

//search
handlerSearch(){let bar = React.findDOMNode(this.refs.searchBar);let value = bar.value;this.props.searchStaff(value);
}

逐步完善ManageSystem以及STAFF类:

ManageSystem.js:


class App extends React.Component {constructor(){super();this.state = {staff : new Staff,staffDetail: null};}//增addStaffItem(item){this.setState({staff: this.state.staff.addStaffItem(item)});}/** 搜索*/searchStaff(word) {this.setState({staff: this.state.staff.searchStaff(word)});}render(){return (<div><StaffHeader searchStaff={this.searchStaff.bind(this)} /><StaffItemPanel items={this.state.staff.staff}}/><StaffFooter addStaffItem={this.addStaffItem.bind(this)}/><StaffDetail/></div>);}
}

STAFF.js


export default class STAFF {constructor(){this.allStaff = [new staffItem(STAFF.rawData[0]),new staffItem(STAFF.rawData[1]),new staffItem(STAFF.rawData[2]),new staffItem(STAFF.rawData[3]),new staffItem(STAFF.rawData[4]),new staffItem(STAFF.rawData[5]),new staffItem(STAFF.rawData[6]),new staffItem(STAFF.rawData[7]),new staffItem(STAFF.rawData[8]),new staffItem(STAFF.rawData[9]),new staffItem(STAFF.rawData[10])];this.staff = this.allStaff;this.word = '';  //搜索关键字}//增addStaffItem(item) {let newItem = new staffItem(item);this.allStaff.push(newItem);this.staff = this.allStaff;return this;}//搜索searchStaff(word){this.word = word;this.staff = this.allStaff;//在staff中搜索this.staff = this.staff.filter(item => {return item.info.name.indexOf(word)!=-1 || (item.info.age+'').indexOf(word)!=-1 || item.info.id.indexOf(word)!=-1 ||item.info.sex.indexOf(word)!=-1;});return this;}
}

依据关键字的搜索功能至此也完成了。

完成接下来的功能
作为示例,第五步以及第六步完成了添加人员以及关键字搜索功能。随后随着功能的不断添加,最终代码的实现会有微小的调整。实现的方法大同小异,请大家对照源码,依照上面的方法逐步完整整个应用。我相信你实现了每一个细节之后,对面入门React一定会有十分大的帮助。
————————————————

关于CSDN软件工程师能力认证

CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准。C系列认证历经近一年的实际线下调研、考察、迭代、测试,并梳理出软件工程师开发过程中所需的各项技术技能,结合企业招聘需求和人才应聘痛点,基于公开、透明、公正的原则,甑别人才时确保真实业务场景、全部上机实操、所有过程留痕、存档不可篡改。C系列认证的宗旨是让一流的技术人才凭真才实学进大厂拿高薪,同时为企业节约大量招聘与培养成本,使命是提升高校大学生的技术能力,为行业提供人才储备,为国家数字化战略贡献力量。

了解详情可点击:CSDN软件工程师能力认证介绍

原文链接:https://blog.csdn.net/a153375250/article/details/52667739

【CSDN软件工程师能力认证学习精选】十分详细的React入门实例相关推荐

  1. #CSDN软件工程师能力认证学习精选# Hadoop基础知识学习

    CSDN软件工程师能力认证是由CSDN制定并推出的一个能力认证标准,宗旨是让一流的技术人才凭真才实学进大厂拿高薪,同时为企业节约大量招聘与培养成本,使命是提升高校大学生的技术能力,为行业提供人才储备, ...

  2. 【CSDN软件工程师能力认证学习精选】吐血整理!140 种 Python 标准库、第三方库和外部工具都有了

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  3. 【CSDN软件工程师能力认证学习精选】Python网络编程(socket编程)

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  4. 【CSDN软件工程师能力认证学习精选】Python可视化库

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  5. 【CSDN软件工程师能力认证学习精选】不用框架,python实现卷积神经网络

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  6. 【CSDN软件工程师能力认证学习精选】如何入门Python与机器学习

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  7. 【CSDN软件工程师能力认证学习精选】机器学习之决策树(Decision Tree)及其Python代码实现

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  8. 【CSDN软件工程师能力认证学习精选】 常见的主流数据库(DBMS)

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  9. 【CSDN软件工程师能力认证学习精选】 什么是前端工程化?

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

  10. 【CSDN软件工程师能力认证学习精选】python | 史上最全的正则表达式

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准.C系列认证历经近一年的实际线下调研.考察.迭代.测试,并梳理出软件工程师开发过程中所需的各项技 ...

最新文章

  1. Xcode7.1环境下上架iOS App到AppStore 流程 (2)
  2. 各排序算法的C++实现与性能测试(转)
  3. 中文BERT上分新技巧,多粒度信息来帮忙
  4. OSI七层模型详解-开放系统互联参考模型详解
  5. java数组数据结构_Java数据结构之数组
  6. linux分区创建ext4失败,RedHat/CentOS ext4无法格式化大分区 补充ext4格式化方式
  7. Dart 语言基础入门 Dart 语言核心库一览
  8. kali卸载firefox_kali 安装最新firefox的悲惨经历
  9. win7 64位安装vs2013后连接远程数据库无法链接,并且导致vs崩溃。
  10. Git来回切换版本的时候,pom文件变黄,每次都需要重新添加到maven以及修改后文件不生效的解决方法
  11. Unity3D射线检测
  12. Tomcat源码解析(一):开坑!手把手教你读Tomcat源码。
  13. 计算机英语听力速记...,2019计算机考研英语听力速记技巧才是王道
  14. python爬微博数据中心,网易微博爬虫(自定义关键字爬取微博数据)(附软件源码)...
  15. 镁光c400-MTFDDAK064M固态硬盘更新固件
  16. NLP--解决Mac OS 10.14.4Python下pip install pyhanlp 失败
  17. omnet++tictoc12案例解析
  18. 卢菲菲记忆课程(一、了解记忆认识大脑)
  19. 常见网络延迟测量方法
  20. python调用百度地图、通过经纬度定位_python调用百度地图API得到两地经纬度计算直线距离...

热门文章

  1. 四川大学 计算机复试分数线,2015年四川大学考研复试分数线已公布
  2. 扬州大学研究生计算机专业分数线,扬州大学考研历年分数线汇总
  3. python turtle 海龟画图歌尔号 火箭 三体 地球
  4. python配置MySQL,需安装MySQL-pyt…
  5. 信息安全快讯丨叶落知秋,e讯知安全
  6. python画兔子代码_Python基础练习实例11(兔子问题)
  7. 50多首经典的广播电台背景音乐推荐下载
  8. 向右箭头代码css,CSS的箭头代码
  9. Unity3D帧动画,图片的切换实现动画效果
  10. CANCELLED: io.grpc.Context was canclled without error