笔记来源:拉勾教育 - 大前端就业集训营
文章内容:学习过程中的笔记、感悟、和经验
管理系统
创建项目
- 创建项目,这里使用脚手架快速创建
- 初始化项目(删除不需要文件、修改响应内容)
组件拆分
整个页面拆分为三个组件,分别是
- 顶部标题部分
- 左侧添加学生
- 右侧学生列表
<!-- public/index.html 页面HTML文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<!-- 引入两个CSS文件 -->
<link rel="stylesheet" href="%PUBLIC_URL%/base.css">
<link rel="stylesheet" href="%PUBLIC_URL%/bootstrap.min.css">
<title>React App</title>
</head>
<body>
<!-- React挂载点 -->
<div id="root"></div>
</body>
</html>
// src/App.js App组件
// 引入React组件和三个页面子组件
import {Component} from 'react'
import Title from './Components/title'
import Left from './Components/left'
import Right from './Components/right'
// App
class App extends Component {
render() {
return (
<div className="container">
{/* 三个组件 */}
<Title />
<Left />
<Right />
</div>
)
}
}
// 导出
export default App
// src/Components/title.js 顶部标题
// 顶部标题,因为是固定内容,所以写成函数组件
function Title() {
return (
// 结构,使用老师提供的结构
<div className="col-md-12">
<h3 className="title">学生信息管理</h3>
</div>
)
}
// 导出
export default Title
// src/Components/left.js 左侧添加学生组件
// raact组件
import {Component} from 'react'
// 左侧添加学生组件
class Left extends Component {
render() {
return (
// 结构,使用老师提供的结构
<div className="col-md-5">
<form>
<div className="form-group">
<label>学号</label>
<input type="number" className="form-control" placeholder="请输入 学号" />
</div>
<div className="form-group">
<label>姓名</label>
<input type="text" className="form-control" placeholder="请输入姓 名" />
</div>
<div className="form-group">
<label>性别 </label>
<label className="checkbox-inline">
<input type="radio" value="男" /> 男
</label>
<label className="checkbox-inline">
<input type="radio" value="女" /> 女
</label>
</div>
<div className="form-group">
<label>年龄</label>
<input type="text" className="form-control" placeholder="请输入姓 名" />
</div>
<div className="form-group">
<label>入学时间</label>
<input className="form-control" type="date" />
</div>
<div className="form-group">
<label>爱好</label>
<div className="checkbox">
<label>
<input type="checkbox" value="足球" /> 足球
</label>
</div>
<div className="checkbox">
<label>
<input type="checkbox" value="篮球" /> 篮球
</label>
</div>
<div className="checkbox">
<label>
<input type="checkbox" value="橄榄球" /> 橄榄球
</label>
</div>
</div>
<div className="form-group">
<label>所属学院</label>
<select className="form-control">
<option value="大前端">大前端</option>
<option value="Java">Java</option>
<option value="python">python</option>
</select>
</div>
<button type="submit" className="btn btn-default">添加</button>
</form>
</div>
)
}
}
// 导出
export default Left
// src/Components/right.js 右侧学生列表
// react组件
import {Component} from 'react'
// 右侧学生列表
class Right extends Component {
render() {
return (
// 使用老师提供的结构
<div className="col-md-6 col-md-offset-1">
<table className="table table-striped table-hover">
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>入学时间</th>
<th>爱好</th>
<th>所属学院</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>01</td>
<td>张三</td>
<td>男</td>
<td>20</td>
<td>2020-08-02</td>
<td>
<span>足球</span>
</td>
<td>python</td>
<td>
<a href="www.baidu.com">删除</a>
<a href="www.baidu.com">修改</a>
</td>
</tr>
</tbody>
</table>
<p className="text-center">无学生信息</p>
<p>总共有 50 个学生</p>
<p>学生的平均年龄是 25</p>
</div>
)
}
}
// 导出
export default Right
这里结构和css文件全部使用老师提供的文件,主要学习的是React处理数据
添加学生信息
除了复选框之外都可以放到state中进行管理
进行数据和结构的绑定
进行数据更新,修改数据调用方法,存到构造函数中,注意继承(super)
控件使用name作为键名
进行爱好复选框渲染,数据绑定和结构搭建
进行复选框的数据更新,不要直接修改,现将数据复制出来,整体进行替换
进行数据提交
提交的时候需要把表单中的信息整合在一起,这里需要筛选选中的爱好(只传递title)
将全部数据存储到App中
当点击提交后,将数据提交给App,利用单向数据流
提交后还原数据(需要注意单选框可能需要更改属性,复选框可能需要深拷贝才能正常使用)
注意setstate是异步的,使用回调的方式避免
// src/App.js App组件添加学生状态数据,创建添加学生方法并把这个方法下放给left(添加学生组件)
// 引入React组件和三个页面子组件
import {Component} from 'react'
import Title from './Components/title'
import Left from './Components/left'
import Right from './Components/right'
// App
class App extends Component {
state = {
// 学生信息数组
students: [
// 书写两个静态学生数据
{
age: "10",
college: "Java",
hobbys: ["足球", "橄榄球"],
name: "cwn",
number: "001",
sex: "男"
},
{
age: "12",
college: "大前端",
hobbys: ["足球"],
name: "stt",
number: "002",
sex: "女"
}
]
}
// 添加学生方法
// 参数1:提交上来的学生数据
// 参数2:回调函数
addStudent = (student, callback) => {
// 深拷贝学生全部数据
const students =JSON.parse(JSON.stringify(this.state.students))
// 把新的学生信息添加进来
students.push(student)
// 用新的学生数据替换旧的数据,然后调用回调函数
this.setState({students}, callback())
}
render() {
return (
<div className="container">
{/* 三个组件 */}
<Title />
{/* 把添加学生方法下放给组件 */}
<Left add={this.addStudent}/>
<Right students={this.state.students} />
</div>
)
}
}
// 导出
export default App
// src/Components/left.js 添加学生组件 - 创建学生状态数据、结构绑定数据、实现数据更改、实现数据提交
// raact组件
import {Component} from 'react'
// 左侧添加学生组件
class Left extends Component {
// 学生信息(默认)
state = {
number: '',
name: '',
sex: '男',
age: '',
college: '大前端',
hobbys: [
{id: 0, title: '足球', isChecked: false},
{id: 1, title: '篮球', isChecked: false},
{id: 2, title: '橄榄球', isChecked: false},
]
}
// 保存默认状态数据
rawDate = JSON.parse(JSON.stringify(this.state))
// 除了爱好之外其他信息输入事件函数
// 参数:事件对象
chageState = (e) => {
// 修改数据
this.setState({
[e.target.name]: e.target.value
})
}
// 爱好修改事件
// 参数:id - 修改的爱好对应id(这里id对应下标),e - 事件对象
changeCollege = (id, e) => {
// 深拷贝爱好数据
const hobbys = JSON.parse(JSON.stringify(this.state.hobbys))
// 修改相应数据
hobbys[id].isChecked = e.target.checked
// 修改状态数据
this.setState({hobbys})
}
// 表单提交事件
// ev - 事件对象
submit = (ev) => {
// 阻止默认行为避免跳转
ev.preventDefault()
// 深拷贝爱好数据
let hobbys = JSON.parse(JSON.stringify(this.state.hobbys))
// 把爱好数据选中的title单独组成数组
hobbys = hobbys.filter(hobby => hobby.isChecked).map(hobby => hobby.title)
// 调用App传递过来的方法添加学生,穿一个回调函数让添加完之后恢复默认数据
this.props.add({...this.state,hobbys},() => this.setState(this.rawDate))
}
render() {
return (
// 结构,使用老师提供的结构
<div className="col-md-5">
<form onSubmit={this.submit}>
<div className="form-group">
<label>学号</label>
{/* 使用name获取对应的数据名,绑定数据,添加onchange方法 下面同理 */}
<input name='number' type="number" className="form-control" placeholder="请输入学号" value={this.state.number} onChange={this.chageState} />
</div>
<div className="form-group">
<label>姓名</label>
<input name='name' type="text" className="form-control" placeholder="请输入姓名" value={this.state.name} onChange={this.chageState} />
</div>
<div className="form-group">
<label>性别 </label>
<label className="checkbox-inline">
<input name='sex' type="radio" value="男" checked={this.state.sex === '男'} onChange={this.chageState}/> 男
</label>
<label className="checkbox-inline">
<input name='sex' type="radio" value="女" checked={this.state.sex === '女'} onChange={this.chageState}/> 女
</label>
</div>
<div className="form-group">
<label>年龄</label>
<input name='age' type="text" className="form-control" placeholder="请输入年龄" value={this.state.age} onChange={this.chageState}/>
</div>
{/* 爱好复选框和前面有区别,但基本逻辑相同 */}
<div className="form-group">
<label>爱好</label>
{this.state.hobbys.map(hobby => {
return (
<div className="checkbox" key={hobby.id}>
<label>
<input type="checkbox" value={hobby.title} onChange={this.changeCollege.bind(this, hobby.id)} checked={hobby.isChecked}/> {hobby.title}
</label>
</div>
)
})}
</div>
<div className="form-group">
<label>所属学院</label>
<select name='college' className="form-control" value={this.state.college} onChange={this.chageState}>
<option value="大前端">大前端</option>
<option value="Java">Java</option>
<option value="python">python</option>
</select>
</div>
<button type="submit" className="btn btn-default">添加</button>
</form>
</div>
)
}
}
// 导出
export default Left
学生信息展示
学生信息数据由App提供
list组件遍历全部学生数据,创建结构,绑定数据
爱好需要二次遍历
老师演示的没有入学日期 ,所以删除入学日期
学生信息删除
可以提前添加一些静态数据用作操作演示
在App组件中定义删除方法
在执行删除之前先询问 - window.confirm
list组件中触发方法,传递值
现将全部数据拿出,然后找到需要删除的数据,最后用这个数据替换掉原数据
使用findIndex找到要删除的位置
// src/App.js 创建删除学生方法,把原始学生数据和删除方法传递给组件
// 引入React组件和三个页面子组件
import {Component} from 'react'
import Title from './Components/title'
import Left from './Components/left'
import Right from './Components/right'
// App
class App extends Component {
state = {
// 学生信息数组
students: [
// 书写两个静态学生数据
{
age: "10",
college: "Java",
hobbys: ["足球", "橄榄球"],
name: "cwn",
number: "001",
sex: "男"
},
{
age: "12",
college: "大前端",
hobbys: ["足球"],
name: "stt",
number: "002",
sex: "女"
}
]
}
// 添加学生方法
// 参数1:提交上来的学生数据
// 参数2:回调函数
addStudent = (student, callback) => {
// 深拷贝学生全部数据
const students =JSON.parse(JSON.stringify(this.state.students))
// 把新的学生信息添加进来
students.push(student)
// 用新的学生数据替换旧的数据,然后调用回调函数
this.setState({students}, callback())
}
// 删除学生方法
// 参数为要删除学生的学号
removeStudent = (number) => {
// 深拷贝学生数组
const students = JSON.parse(JSON.stringify(this.state.students))
// 寻找到对应学好学生的索引值
const index = students.findIndex(s => s.number === number)
// 调用数组方法删除学生
students.splice(index, 1)
// 把更新后的数据替换进去
this.setState({students})
}
render() {
return (
<div className="container">
{/* 三个组件 */}
<Title />
{/* 把添加学生方法下放给组件 */}
<Left add={this.addStudent}/>
{/* 把学生数据和删除学生方法传递给学生列表 */}
<Right students={this.state.students} remove={this.removeStudent} />
</div>
)
}
}
// 导出
export default App
// src/Components/right.js 遍历全部学生数据,创建结构绑定数据,添加删除按钮点击事件执行app传递过来的删除学生方法// react组件import {Component} from 'react'// 右侧学生列表class Right extends Component { // 删除按钮点击事件 // 参数1:删除学生学号 removeClick = (number, e) => { // 禁止默认行为 e.preventDefault() // 删除之前要先确认一次 if (window.confirm('您确认要删除吗?')) { // 确认删除调用删除学生方法 this.props.remove(number) } } render() { return ( // 使用老师提供的结构 <div className="col-md-6 col-md-offset-1"> <table className="table table-striped table-hover"> <thead> <tr> <th>学号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>入学时间</th> <th>爱好</th> <th>所属学院</th> <th>操作</th> </tr> </thead> <tbody> {/* 遍历全部学生创建结构 */} {this.props.students.map(student => { return ( <tr key={student.number}> <td>{student.number}</td> <td>{student.name}</td> <td>{student.sex}</td> <td>{student.age}</td> <td> {student.hobbys.map((hobby, index) => { return (<span key={index}>{hobby}</span>) })} </td> <td>{student.college}</td> <td> {/* 删除按钮添加点击事件 */} <a href="www.lagou.com" onClick={this.removeClick.bind(this,student.number)}>删除</a> <a href="www.lagou.com">修改</a> </td> </tr> ) })} </tbody> </table> <p className="text-center">无学生信息</p> <p>总共有 50 个学生</p> <p>学生的平均年龄是 25</p> </div> ) }}// 导出export default Right
计算平均值等
修改功能暂时不能实现,删除掉
无学生信息判断当前学生信息是否为空,有学生信息则不显示
学生个数直接获取即可
平均年龄需要计算全部学生的平均值,可能需要取整操作
// src/Components/right.js 完善其他功能:无学生信息动态现实和隐藏、总人数、平均年龄// react组件import {Component} from 'react'// 右侧学生列表class Right extends Component { // 删除按钮点击事件 // 参数1:删除学生学号 removeClick = (number, e) => { // 禁止默认行为 e.preventDefault() // 删除之前要先确认一次 if (window.confirm('您确认要删除吗?')) { // 确认删除调用删除学生方法 this.props.remove(number) } } // 计算平均值方法 averageAge = () => { // 累加器 let sum = 0 // 遍历全部学生实现年龄累加 this.props.students.map(s => { sum += Number(s.age) }) // 返回平均值 return Math.floor(sum /this.props.students.length) } render() { return ( // 使用老师提供的结构 <div className="col-md-6 col-md-offset-1"> <table className="table table-striped table-hover"> <thead> <tr> <th>学号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>入学时间</th> <th>爱好</th> <th>所属学院</th> <th>操作</th> </tr> </thead> <tbody> {/* 遍历全部学生创建结构 */} {this.props.students.map(student => { return ( <tr key={student.number}> <td>{student.number}</td> <td>{student.name}</td> <td>{student.sex}</td> <td>{student.age}</td> <td> {student.hobbys.map((hobby, index) => { return (<span key={index}>{hobby}</span>) })} </td> <td>{student.college}</td> <td> {/* 删除按钮添加点击事件 */} <a href="www.lagou.com" onClick={this.removeClick.bind(this,student.number)}>删除</a> <a href="www.lagou.com">修改</a> </td> </tr> ) })} </tbody> </table> {/* 使用三元表达式动态设置显示和隐藏 */} {this.props.students.length > 0 ? null : <p className="text-center">无学生信息</p>} {/* 直接使用长度即可 */} <p>总共有 {this.props.students.length} 个学生</p> {/* 调用方法获取平均值 */} <p>学生的平均年龄是 {this.averageAge()}</p> </div> ) }}// 导出export default Right
