React案例1

一、案例要求:

1.实现组件分类,分为头部输,列表,底部

2.实现输入任务名称渲染到列表里

3.单独删除任务

4.全选与全不选

5.删除勾选任务

二、实现原理

1.完成组件创建

2.通过ref绑定输入框的值,在通过自定义方法参数传回app.js中通过setstate改变列表中渲染数组的值

3. 通过确定被点击的元素数组id值传回app.js再通过filter方法返回id值不为传回id值的新数组,实现删除功能

4.通过循环判断传回值改变state里的值从而改变勾选状态

5.创建一个通过循环判断是否被勾选再通过filter方法传回新数组的方法在把方法放到底部组件进行调用

三、代码:

App.js

/*
 * @Author: wu07 [email protected]
 * @Date: 2023-02-14 16:31:46
 * @LastEditors: wu07 [email protected]
 * @LastEditTime: 2023-02-17 09:27:23
 * @FilePath: \react\day05\demo02\tode\src\App.js
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import React, { Component } from 'react';
import Header from './components/Header';
import List from './components/List';
import Footer from './components/Footer';
import './App.css';
export default class App extends Component {
  state = {
    todos: [
      { id: '001', name: '吃饭', done: true },
      { id: '002', name: '睡觉', done: true },
      { id: '003', name: '打代码', done: false },
      { id: '004', name: '逛街', done: false }
    ]
  };
  addTodo = (e) => {
    const todos = this.state.todos;
    const newTodos = [e, ...todos];
    this.setState({ todos: newTodos });
  };

  change = (e) => {
    const todos = this.state.todos;
    this.setState({ todos: e });
  };
  updateTodo = (id, done) => {
    const { todos } = this.state;
    const newTodos = todos.map((todoObj) => {
      if (todoObj.id === id) return { ...todoObj, done };
      else return todoObj;
    });
    this.setState({ todos: newTodos });
  };
  Delete = (id) => {
    const todos = this.state.todos;
    const newTodos = todos.filter((e) => {
      return e.id !== id;
    });
    this.setState({ todos: newTodos });
  };
  delete = () => {
		const newTodos =this.state.todos.filter((e)=>{
			return !e.done
		})
		this.setState({todos:newTodos})
  };
  render() {
    return (
      <div className="todo-container">
        <div className="todo-wrap">
          <Header addTodo={this.addTodo} Delete={this.Delete} />
          <List todos={this.state.todos} updateTodo={this.updateTodo} Delete={this.Delete} />
          <Footer todos={this.state.todos} change={this.change} delete={this.delete} />
        </div>
      </div>
    );
  }
}

components/Footer/index.jsx

/*
 * @Author: wu07 [email protected]
 * @Date: 2023-02-14 16:36:54
 * @LastEditors: wu07 [email protected]
 * @LastEditTime: 2023-02-17 09:20:13
 * @FilePath: \react\day05\demo02\tode\src\components\Footer\index.jsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import React, { Component } from 'react';
import './index.css';
export default class Footer extends Component {
    state = {
        flag: false,
    };
    // (function name(params) {
    //     console.log(111);
    // }());
    allCheck = () => {
        this.state.flag = !this.state.flag;
        const todos = this.props.todos;
        todos.map((e) => {
            if (this.state.flag == true) {
                e.done = true;
            }
            else {
                e.done = false;
            }
        });
        this.props.change(todos);
    };
    delete = () => {
        this.props.delete();
    };
    render() {
        //pre初始值
        const doneCount = this.props.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0);
        return (
            <div className="todo-footer">
                <label>
                    <input type="checkbox" checked={this.state.flag = doneCount == 4 ? true : false} onChange={this.allCheck} />
                </label>
                <span>
                    <span>已完成{doneCount}</span> / 全部{this.props.todos.length}
                </span>
                <button className="btn btn-danger" onClick={this.delete}>清除已完成任务</button>
            </div>
        );
    }
}

components/Footer/index.css

/*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;
    margin-right: 5px;
}

.todo-footer button {
    float: right;
    margin-top: 5px;
}

components/List/index.jsx

/*
 * @Author: wu07 [email protected]
 * @Date: 2023-02-14 16:37:07
 * @LastEditors: wu07 [email protected]
 * @LastEditTime: 2023-02-15 17:22:04
 * @FilePath: \react\day05\demo02\tode\src\components\List\index.jsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import React, { Component } from 'react';
import './index.css';
import Item from '../Item';
export default class List extends Component {
    render() {
        const { todos, updateTodo, Delete } = this.props;
        return (
            <ul className="todo-main">
                {
                    todos.map(todo => {
                        return <Item key={todo.id} {...todo} updateTodo={updateTodo} Delete={Delete} />;
                    })
                }
            </ul>
        );
    }
}

components/List/index.css

/*main*/
.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*/
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;
}

components/Item/index.jsx

/*
 * @Author: wu07 [email protected]
 * @Date: 2023-02-14 16:37:05
 * @LastEditors: wu07 [email protected]
 * @LastEditTime: 2023-02-15 17:21:07
 * @FilePath: \react\day05\demo02\tode\src\components\Item\index.jsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import React, { Component } from 'react';
import './index.css';
export default class Item extends Component {
    state = {
        mouse: false
    };
    change = (e) => {
        this.props.updateTodo(this.props.id, e.target.checked);
    };
    Enter = () => {
        this.setState({
            mouse: true
        });
    };
    Leave = () => {
        this.setState({
            mouse: false
        });
    };
    Delete = () => { this.props.Delete(this.props.id); };


    render() {
        return (
            <div onMouseEnter={this.Enter} onMouseLeave={this.Leave}><li>
                <label>
                    <input type="checkbox" checked={this.props.done} onChange={this.change} />
                    <span>{this.props.name}</span>
                </label>
                <button className="btn btn-danger" style={
   
   { display: this.state.mouse ? 'block' : 'none' }} onClick={this.Delete}>删除</button>
            </li>
            </div>
        );
    }
}

components/Item/index.css

/*item*/
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;
}

components/Header/index.jxs

/*
 * @Author: wu07 [email protected]
 * @Date: 2023-02-14 16:37:03
 * @LastEditors: wu07 [email protected]
 * @LastEditTime: 2023-02-15 13:23:06
 * @FilePath: \react\day05\demo02\tode\src\components\Header\index.jsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import React, { Component } from 'react';
import './index.css';
import { nanoid } from 'nanoid';
export default class Header extends Component {
    handleKeyUp = (e) => {
        if (e.keyCode != 13) {
            return;
        }
        if (e.target.value.trim() === '') {
            alert("输入不能为空");
            return;
        }
        //nanoid()方法生成唯一id标识符
        const a = { id: nanoid(), name: e.target.value, done: false };
        this.props.addTodo(a);
        //清空输入
        e.target.value = '';
    };
    render() {
        return (
            <div className="todo-header">
                <input type="text" placeholder="请输入你的任务名称,按回车键确认" onKeyUp={this.handleKeyUp} />
            </div>
        );
    }
}

components/Header/index.css

/*header*/
.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);
}

四、小结

这个小案例里有数据传递渲染和组件导入使用,符合初学react的朋友。

猜你喜欢

转载自blog.csdn.net/xiaowu1127/article/details/129092578