React hace todo
- 1. Estructura del proyecto de diseño
- Segundo, divida los componentes para lograr páginas estáticas
- 3. Función 1_Añadir información de la tarea a la primera línea
- 4. Función 2_ Cuando el mouse se mueve en la lista, se resaltará y se mostrará el botón "Eliminar".
- Cinco, función 3_ haciendo clic en la casilla de verificación, cambie el hecho en el estado
- Seis, función 4_ eliminar una tarea pendiente
- 7. Función 5_ Realice la función de seleccionar todo y borrar en la parte inferior
- 8. Resumen del caso
1. Estructura del proyecto de diseño
Debido a que implementamos todo como un componente funcional, las ideas básicas de diseño son:
1. Cree una nueva carpeta de tareas pendientes en componentes, cree un nuevo index.jsx como componente de tareas pendientes y coloque algunos componentes de tareas pendientes en esta carpeta.
2. Introducir el componente en App.jsx
import Todo from './components/Todo'
y renderizarlo en render:
import React, { Component } from 'react';
import Todo from './components/Todo';
export default class APP extends Component {
render() {
return (
<div id="root">
<Todo />
</div>
);
}
}
Segundo, divida los componentes para lograr páginas estáticas
1. Dividimos el componente de tareas pendientes en cuatro partes: Encabezado, Lista, Elemento y Pie de página
2. Cree cuatro carpetas nuevas: Encabezado, Lista, Elemento y Pie de página en la carpeta de tareas pendientes, y cree nuevos index.jsx e index.css en ellas respectivamente.
3. Complete los recursos estáticos en jsx y css respectivamente
Todo文件夹
/*Todo/index.jsx*/
import React, { Component } from 'react';
import './index.css'
import Footer from './Footer';
import Header from './Header';
import List from './List';
export default class Todo extends Component {
render() {
return (
<div id="root">
<div className="todo-container">
<div className="todo-wrap">
<Header />
<List />
<Footer />
</div>
</div>
</div>
);
}
}
/*Todo/index.css--公用样式*/
body {
background: #fff;
}
.btn {
display: inline-block;
padding: 4px 12px;
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-danger {
color: #fff;
background-color: #da4f49;
border: 1px solid #bd362f;
}
.btn-danger:hover {
color: #fff;
background-color: #bd362f;
}
.btn:focus {
outline: none;
}
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
Header文件夹
/*Header/index.jsx*/
import React, { Component } from 'react';
import './index.css'
export default class Header extends Component {
render() {
return (
<div className="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" />
</div>
)
}
}
/*header/index.css*/
.todo-header input {
width: 560px;
height: 28px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
}
.todo-header input:focus {
outline: none;
border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
List文件夹
/*List/index.jsx*/
import React, { Component } from 'react';
import Item from '../Item';
import './index.css'
export default class List extends Component {
render() {
return (
<ul className="todo-main">
<Item />
</ul>
);
}
}
/*List/index.css*/
.todo-main {
margin-left: 0px;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0px;
}
.todo-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
Item文件夹
/*Item/index.jsx*/
import React, { Component } from 'react';
import './index.css'
export default class Item extends Component {
render() {
return (
<div>
<li>
<label>
<input type="checkbox" />
<span></span>
</label>
<button className="btn btn-danger" style={
{ display: 'none' }}>删除</button>
</li>
</div>
);
}
}
/*Item/index.css*/
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}
li button {
float: right;
display: none;
margin-top: 3px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
Footer文件夹
/*Footer/index.jsx*/
import React, { Component } from 'react';
import './index.css'
export default class Footer extends Component {
render() {
return (
<div className="todo-footer">
<label>
<input type="checkbox" />
</label>
<span>
<span>已完成0</span> / 全部2
</span>
<button className="btn btn-danger">清除已完成任务</button>
</div>
);
}
}
/*Footer/index.css*/
.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;
margin-right: 5px;
}
.todo-footer button {
float: right;
margin-top: 5px;
}
3. Función 1_Añadir información de la tarea a la primera línea
因为涉及到兄弟组件之间的传值,所以我们这里需要通过与父组件的Props传值方法
1. Primero, configure el número analógico en el componente principal (Todo/index.jsx) y páselo a la Lista de componentes secundarios.
/*Todo/index.jsx*/
import React, { Component } from 'react';
import './index.css'
import Footer from './Footer';
import Header from './Header';
import List from './List';
export default class APP extends Component {
state = {
todos: [{
id: '001',
name: '吃饭',
done: true
}, {
id: '002',
name: '睡觉',
done: true
}]
}
render() {
const { todos } = this.state
return (
<div id="root">
<div className="todo-container">
<div className="todo-wrap">
<Header />
<List todos={todos} />
<Footer />
</div>
</div>
</div>
);
}
}
2. El componente List recibe los Props pasados desde el componente principal Todo y transmite el valor al subcomponente Item de List para su visualización.
/*List/index.jsx*/
import React, { Component } from 'react';
import Item from '../Item';
import './index.css'
export default class List extends Component {
render() {
const { todos } = this.props;
return (
<ul className="todo-main">
{
todos.map((item) => {
return <Item key={item.id} {...item} />
})
}
</ul>
);
}
}
3. El componente Item recibe los accesorios de la lista del componente principal y los muestra.
import React, { Component } from 'react';
import Item from '../Item';
import './index.css'
export default class List extends Component {
render() {
const { todos } = this.props;
return (
<ul className="todo-main">
{
todos.map((item) => {
return <Item key={item.id} {...item} />
})
}
</ul>
);
}
}
4. El componente principal Todo obtiene los datos agregados en el encabezado del componente secundario a través de la función de transferencia de accesorios (addTodo)
import React, { Component } from 'react';
import './index.css'
import Footer from './Footer';
import Header from './Header';
import List from './List';
export default class APP extends Component {
state = {
todos: [{
id: '001',
name: '吃饭',
done: true
}, {
id: '002',
name: '睡觉',
done: true
}]
}
//用于添加一个todo,参数为todo对象
addTodo = (todoObj) => {
let { todos } = this.state;
//将输入的内容放到数组第一位
todos.unshift(todoObj);
//修改状态
this.setState(todos)
}
render() {
const { todos } = this.state
return (
<div id="root">
<div className="todo-container">
<div className="todo-wrap">
<Header addTodo={this.addTodo} />
<List todos={todos} />
<Footer />
</div>
</div>
</div>
);
}
}
5. El componente Header ejecuta la función pasada desde el componente principal Todo al escuchar la "tecla Enter" para actualizar el estado
nanoid的作用是生成唯一的值,主要为了给元素的key进行赋值
import React, { Component } from 'react';
//类似于uuid,生成唯一的id
import { nanoid } from 'nanoid';
import './index.css'
export default class Header extends Component {
handleKeyUp = (event) => {
const { keyCode, target } = event;
if (keyCode === 13) {
//这里还需要判断空格的多种情况(正则)
if (target.value !== "") {
const newTodo = { id: nanoid(), name: target.value, done: false };
this.props.addTodo(newTodo);
//清空输入的内容
target.value = ""
}
}
}
render() {
return (
<div className="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" onKeyUp={this.handleKeyUp} />
</div>
)
}
}
4. Función 2_ Cuando el mouse se mueve en la lista, se resaltará y se mostrará el botón "Eliminar".
此功能主要通过鼠标的移入移出事件进行判断,高亮的功能可以通过css中的:hover实现,本案例使用React中的方法
1. Definir el estado del componente
state = { mouseType: false }
2. Defina los eventos de movimiento de entrada y salida del mouse, verdadero significa movimiento hacia adentro, falso significa movimiento hacia afuera, y el color de fondo y la visualización se representan de acuerdo con el valor de mouseType en el estado. (Esto se implementa usando el método curry de funciones de orden superior)
import React, { Component } from 'react';
import './index.css'
export default class Item extends Component {
state = { mouseType: false }
//鼠标移入移出事件
handleMouse = (mouseType) => {
return () => {
this.setState({ mouseType })
}
}
render() {
const { name, done } = this.props
return (
<div>
<li style={
{ backgroundColor: this.state.mouseType ? '#ddd' : 'white' }} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>
<label>
<input type="checkbox" defaultChecked={done} />
<span>{name}</span>
</label>
<button className="btn btn-danger" style={
{ display: this.state.mouseType ? 'block' : 'none' }}>删除</button>
</li>
</div>
);
}
}
Cinco, función 3_ haciendo clic en la casilla de verificación, cambie el hecho en el estado
1. Porque para implementar el componente secundario Item para modificar el estado en el componente principal Todo de la lista del componente principal, es necesario definir la función updateTodo en el componente principal Todo y pasarla al componente Item a través de accesorios.
/*Todo/index.jsx*/
//用于更新todo,参数为id
updateTodo = (id, done) => {
const { todos } = this.state;
let newTodos = todos.map((item) => {
if (item.id === id) {
return { ...item, done }
} else {
return item
}
})
this.setState({ todos: newTodos })
}
<List todos={todos} updateTodo={this.updateTodo} />
List/index.jsx
<Item key={item.id} {...item} updateTodo={updateTodo} />
2. En el componente Elemento, agregue un evento onChange a la casilla de verificación y pase la identificación de la tarea pendiente correspondiente a la casilla de verificación seleccionada actualmente como parámetro para handleCheck
<input type="checkbox" defaultChecked={done} onChange={this.handleCheck(id)} />
3. En la función handleCheck, ejecute el id y el checkbox actual como parámetros de updateTodo
//勾选或者取消勾选
handleCheck = (id) => {
return (event) => {
this.props.updateTodo(id, event.target.checked)
}
}
4. Introduzca la biblioteca prop-types para limitar los accesorios de cada componente (vea cómo usar: npm.com prop-types )
/*以Item/index.jsx为例*/
//对props进行限制
static propTypes = {
updateTodo: PropTypes.func.isRequired,
done: PropTypes.bool.isRequired
}
Seis, función 4_ eliminar una tarea pendiente
1. La lógica es la misma que la forma de modificar hecho Primero, en el componente Elemento, vincule onClick al botón Eliminar
<button onClick={this.handleDel(id)} className="btn btn-danger" style={
{ display: this.state.mouseType ? 'block' : 'none' }}>删除</button>
2. Defina la función handleDel y ejecute la función deleteTodo pasada desde el componente Todo
//删除一个todo
handleDel = (id) => {
return () => {
this.props.deleteTodo(id)
}
}
3. Defina la función deleteTodo en el componente Todo, pásela al subcomponente List y luego pásela al subcomponente Item a través del componente List.
Todo/index.jsx
//删除指定todo对象
deleteTodo = (id) => {
const { todos } = this.state;
const newTodos = todos.filter(item => {
return item.id !== id
})
this.setState({ todos: newTodos })
}
<List todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo} />
List/index.jsx
<Item key={item.id} {...item} updateTodo={updateTodo} deleteTodo={deleteTodo} />
7. Función 5_ Realice la función de seleccionar todo y borrar en la parte inferior
1. Primero realiza las estadísticas del número completado y todos los números
Footer/index.jsx
const { todos } = this.props
//已完成数
const doneCount = todos.reduce((pre, current) => {
return current.done === true ? ++pre : pre
}, 0)
<span>
<span>已完成{doneCount}</span> / 全部{todos.length}
</span>
2. Implementar la función de seleccionar todo
Footer/index.jsx
<input type="checkbox" checked={doneCount === todos.length && todos.length !== 0 ? true : false} onChange={this.handleCheckAll} />
//全选
handleCheckAll = (event) => {
this.props.checkAllTodo(event.target.checked)
}
3. Debido a que desea cambiar el estado de los datos, debe definir una función en el componente principal Todo y pasarla a través de accesorios.
Todo/index.jsx
//全选
checkAllTodo = (done) => {
const { todos } = this.state;
let newTodos = todos.map(item => {
return { ...item, done: done }
})
this.setState({ todos: newTodos })
}
<Footer todos={todos} checkAllTodo={this.checkAllTodo} />
4. Realice la función de compensación completada
Footer/index.jsx
<button className="btn btn-danger" onClick={this.handleClear}>清除已完成任务</button>
//清除已完成任务
handleClear = () => {
this.props.clearAllDone()
}
5. Debido a que desea cambiar el estado de los datos, debe definir una función en el componente principal Todo y pasarla a través de accesorios.
Todo/index.jsx
//清除所有已完成
clearAllDone = () => {
const { todos } = this.state;
const newTodos = todos.filter(item => {
return item.done === false
})
this.setState({ todos: newTodos })
}
<Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone} />
8. Resumen del caso
1. Dividir componentes e implementar componentes estáticos Nota: la escritura de className y style
2. Lista de inicialización dinámica, cómo determinar en qué estado del componente colocar los datos
Un componente usa: ponerlo en su propio estado
Uso de algunos componentes: colóquelos en su estado de componente principal común (oficialmente llamado promoción estatal )
3. En cuanto a la comunicación entre padre e hijo:
(1) [Componente principal] pasa datos a [componente secundario] a través de accesorios
(2) [Componente secundario] pasa datos a [componente principal]: pasa a través de accesorios, lo que requiere que [componente principal] pase una función a [componente secundario] por adelantado
4. Preste atención a la diferencia entre defaultChecked y Checked, similar a defaultValue y Value
5. ¿Dónde está el estado, dónde está el método de funcionamiento del estado?
Dirección de origen: https://gitee.com/daiwanghao/react-family-bucket.git
Para ver el contenido de las tareas realizadas por React arriba, preste atención a la columna " Cubo de la familia React ".
Compartiré los problemas comunes en mis proyectos habituales y el conocimiento de la prueba escrita y la entrevista contigo en CSDN, y progresaremos juntos.