前言
在企业中应用react进行项目开发,都是基于react的脚手架,我们称之为SPA(Singer Page Application)应用。在这些应用中,我们会用到路由,网络,状态管理等等全家桶体系的知识,也会进一步运用ES6/7语法,构架工具,架构,设置模式等。
什么是React脚手架:
1)react脚手架是用来帮助我们快速创建一个基于react库的模板项目,主要包括三部分:模板项目所有需要的配置,模板项目所有需要的依赖,安装/运行/编译环境,可以直接跑起来。
2)使用脚手架开发的项目一定是要遵循模块化、组件化、工程化的;在react中提供了一个用于创建react项目的脚手架库:create-react-app。
3)通常项目的整体技术配置是:react+react-??+webpack+ es6/7 + eslint.
React.png操作步骤:
1)全局安装creact-react-app
2)创建一个脚手架项目
create-react-app (项目名称)demo
cd (项目名称)demo
npm start
也可以用yarn (在React中大多数都是使用yarn来跑项目)
目录:
- node_module
- 各依赖
- public
- index.html
- src
- App.css/App.js/App.test.js
- index.js/index.css
- package-lock.json
- package.json
- README.md
运行流程
运行之后首先进入src下的index.js,然后进入App.js,再其次往下进入其它文件。
为什么采用单向数据流:防止多个子组件同时修改数据
React可以与三方框架并存。
React只负责挂载的DOM节点,其它的节点可以运用其它的框架,react不会影响其使用。注意:要保证其它框架不会影响React的使用
完成todolist案例
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
App.js
import React, {Component} from 'react';
import Head from './components/Head'
import List from './components/List'
import Foot from './components/Foot'
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
{id: 1, title: '学习React课程', finished: false},
{id: 2, title: '刷半小时电视剧', finished: false},
{id: 3, title: '学习Java的课程', finished: false},
{id: 4, title: '学习Python的课程', finished: false},
],
finishedCount: 0
}
}
// 1. 修改完成状态
changeTodoFinished = (todoId, isFinished) => {
// 1.1 遍历
const tempTodos = this.state.todos;
let finishedCount = 0;
tempTodos.forEach((todo, index) => {
if (todo.id === todoId) {
todo.finished = isFinished;
}
if (todo.finished) {
finishedCount += 1;
}
});
// 2.3 更新状态
this.setState({
todos: tempTodos,
finishedCount
})
};
// 2. 删除一条记录
removeTodoWithId = (todoId) => {
// 2.1 遍历
const tempTodos = this.state.todos;
let finishedCount = 0;
tempTodos.forEach((todo, index) => {
if (todo.id === todoId) {
tempTodos.splice(index, 1);
}
});
// 2.2 处理选中的
tempTodos.forEach((todo, index) => {
if (todo.finished) {
finishedCount += 1;
}
});
// 2.3 更新状态
this.setState({
todos: tempTodos,
finishedCount
})
};
// 3. 添加一个todo
addOneTodo = (todo) => {
// 3.1 取出数组
let tempTodos = this.state.todos;
tempTodos.push(todo);
// 3.2 更新状态
this.setState({
todos: tempTodos
})
};
// 4. 删除已经完成的所有任务
delCheckedTodo = () => {
// 4.1 取出对象
let tempTodos = this.state.todos;
let tempArr = [];
tempTodos.forEach((todo, index) => {
if (!todo.finished) {
tempArr.push(todo);
}
});
// 4.2 更新状态
this.setState({
todos: tempArr,
finishedCount: 0
})
};
// 5. 选中/取消所有
dealSelectedAllTodo = (flag)=>{
// 5.1 遍历
const tempTodos = this.state.todos;
let finishedCount = 0;
tempTodos.forEach((todo, index) => {
todo.finished = flag;
});
// 5.2 处理选中的
tempTodos.forEach((todo, index) => {
if (todo.finished) {
finishedCount += 1;
}
});
// 5.3 更新状态
this.setState({
todos: tempTodos,
finishedCount
})
};
render() {
const {todos, finishedCount} = this.state;
return (
<div className="todo-container">
<div className="todo-wrap">
{/*头部*/}
<Head
lastTodoId={todos.length === 0 ? 0 : todos[todos.length - 1].id}
addOneTodo={this.addOneTodo}
/>
{/*列表*/}
<List
todos={todos}
removeTodoWithId={this.removeTodoWithId}
changeTodoFinished={this.changeTodoFinished}
/>
{/*尾部*/}
<Foot
finishedCount={finishedCount}
totalCount={todos.length}
delCheckedTodo={this.delCheckedTodo}
dealSelectedAllTodo={this.dealSelectedAllTodo}
/>
</div>
</div>
);
}
}
export default App;
index.css
body {background: rgb(248, 244, 244);}
.btn {
display: inline-block;
padding: 8px 10px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
text-align: center;
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
.btn-warning {
color: #fff;
background-color: orange;
border: none;
}
.btn-warning:hover {
color: #fff;
background-color: red;
}
.btn:focus {
outline: none;
}
/*app*/
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
/*header*/
.todo-header input {
width: 560px;
height: 28px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
outline: none;
}
.todo-header input:focus {
outline: none;
border-color: rgba(255, 0, 0, 0.8);
box-shadow: inset 0 1px 1px rgba(255, 0, 0, 0.075), 0 0 8px rgba(255, 0, 0, 0.6);
}
/*main*/
.todo-main {
margin-left: 0;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0;
}
.todo-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
/*item*/
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
li label {
cursor: pointer;
}
li button.btn {
display: none;
margin-top: 3px;
padding: 3px 10px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
/*footer*/
.todo-footer {
height: 40px;
line-height: 40px;
padding-left: 6px;
margin-top: 5px;
}
.todo-footer label {
display: inline-block;
margin-right: 20px;
cursor: pointer;
}
.todo-footer label input {
position: relative;
top: -1px;
vertical-align: middle;
}
.todo-footer button {
float: right;
margin-top: 5px;
}
Foot.jsx
import React, {Component} from 'react';
import PropTypes from 'prop-types';
export default class Foot extends Component{
static propTypes = {
finishedCount: PropTypes.number.isRequired, // 已经完成的任务数量
totalCount: PropTypes.number.isRequired, // 总任务数量
delCheckedTodo: PropTypes.func.isRequired, // 删除已经完成的所有任务
dealSelectedAllTodo: PropTypes.func.isRequired // 选中/取消所有
};
render() {
const {finishedCount, totalCount, delCheckedTodo, dealSelectedAllTodo} = this.props;
return (
<div className="todo-footer">
<label>
<input
type="checkbox"
checked={finishedCount === totalCount}
onChange={()=>dealSelectedAllTodo(finishedCount !== totalCount)}
/>
</label>
<span><span>已完成{finishedCount}件</span> / 总计{totalCount}件</span>
<button
className="btn btn-warning"
onClick={()=>delCheckedTodo()}
>
清除已完成任务
</button>
</div>
)
}
}
Head.jsx
import React, {Component} from 'react';
import PropTypes from 'prop-types';
export default class Head extends Component{
constructor(props){
super(props);
// 绑定ref
this.myInput = React.createRef();
}
static propTypes = {
lastTodoId: PropTypes.number.isRequired, // 最后一条记录的ID
addOneTodo: PropTypes.func.isRequired // 添加一条记录
};
render() {
return (
<div className="todo-header">
<input
ref={this.myInput}
type="text"
placeholder="请输入今天的任务清单,按回车键确认"
onKeyDown={(e)=>this._handleEvent(e)}
/>
</div>
)
}
_handleEvent(e){
const {lastTodoId, addOneTodo} = this.props;
// 1. 判断是否是回车键
if(13 === e.keyCode){
// 2. 判断输入的内容是否为空
if(!this.myInput.current.value){
alert('输入的内容不能为空!');
return;
}
// 3. 创建todo对象返回
const todo = {id: lastTodoId + 1, title: this.myInput.current.value, finished: false};
addOneTodo(todo);
// 4. 清空内容
this.myInput.current.value = '';
}
}
}
Item.jsx
import React, {Component} from 'react';
import PropTypes from 'prop-types';
export default class Item extends Component{
constructor(props){
super(props);
this.state = {
showDelBtn: false
}
}
static propTypes = {
todo: PropTypes.object.isRequired, // 单条数据
removeTodoWithId: PropTypes.func.isRequired, // 删除一条记录
changeTodoFinished: PropTypes.func.isRequired, // 删除一条记录
};
render() {
const {todo, removeTodoWithId, changeTodoFinished} = this.props;
const {showDelBtn} = this.state;
return (
<li
onMouseOver={()=>this._hasShowBtn(true)}
onMouseOut={()=>this._hasShowBtn(false)}
>
<label>
<input type="checkbox" checked={todo.finished} onChange={()=>changeTodoFinished(todo.id, !todo.finished)}/>
<span>{todo.title}</span>
</label>
<button
className="btn btn-warning"
style={{display: showDelBtn ? 'block' : 'none'}}
onClick={()=>removeTodoWithId(todo.id)}
>
删除
</button>
</li>
)
}
// 处理按钮的显示和隐藏
_hasShowBtn(flag){
this.setState({
showDelBtn: flag
})
}
}
List.jsx
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Item from './Item';
export default class List extends Component {
static propTypes = {
todos: PropTypes.array.isRequired, // 数据数组
removeTodoWithId: PropTypes.func.isRequired, // 删除一条记录
changeTodoFinished: PropTypes.func.isRequired, // 删除一条记录
};
render() {
const {todos, removeTodoWithId, changeTodoFinished} = this.props;
return (
<ul className="todo-main">
{
todos.map((todo, index) => (
<Item
key={index}
todo={todo}
removeTodoWithId={removeTodoWithId}
changeTodoFinished={changeTodoFinished}
/>
))
}
</ul>
)
}
}
工程篇.png
网友评论