美文网首页
使用 React Hooks + mock + antd构建一

使用 React Hooks + mock + antd构建一

作者: 梁坤同学 | 来源:发表于2019-12-01 23:17 被阅读0次

    实现效果:

    todoList.gif

    搭建项目

    使用 create-react-app 快速创建一个项目,删除不必要的文件,保留文件如下:


    文件目录

    目录说明

    • index.js - 项目入口文件
    • index.less - 样式
    • mock.js - 模拟 todo 数据
    • TodoList.js - 实现的逻辑文件

    在项目中引入 antd,具体方法见 在 create-react-app 中使用 antd

    各部分代码展示

    mock.js
    // 引入 mock 模拟数据
    import Mock from 'mockjs'
    
    const Random = Mock.Random
    
    Random.extend({
      planInfo: function(date) {
        const Info = ["吃饭", "睡觉", "打豆豆"]
        return this.pick(Info)
      }
    })
    
    const data = Mock.mock('/fakeData', 'get', {
      success: true,
      message: 'success',
      todoList: {
        "filter": "SHOW_ALL",
        "list|1-10": [
          {
            "id|+1": 1,
            "content": '@planInfo',
            "isDone": Random.boolean(),
            "dataTime": Random.date('yyyy-MM-dd')
          },
        ]
      }
    })
    
    export default data
    
    TodoList.js
    import React, { useState, useEffect } from "react";
    import axios from "axios";
    import "./mock";
    
    import { Input, List, Button, Icon } from "antd";
    
    const { Search } = Input;
    
    export default function TodoList() {
      //  data - 完整的 todo 数据
      const [data, setData] = useState([]);
    
      // 在此处请求接口数据并初始化 todoList,
      //  useEffect 传入第二个参数为空数组,使得该 effect 仅执行一次
      useEffect(() => {
        (async () => {
          const res = await axios.get("/fakeData");
          const { list } = res.data.todoList;
          setData(list);
        })();
      }, []);
    
      // 展示的数据,之所以出现需要出现这个数据,
      // 是因为我们的所有操作都是在前端完成的,不存在请求接口调用数据。  
      // 那么我们在进行展示 "已完成" "未完成" 的不同任务时,就需要全部的数据不会被覆盖,showArr 只负责数据
      const [showArr, setShowArr] = useState([].concat(data));
    
      // 当 data 发生改变时,执行该 effect,替换 showArr
      useEffect(() => {
        setShowArr([].concat(data));
      }, [data]);
    
      // 实现任务输入框的双向绑定
      const [inputValue, setInputValue] = useState("");
    
      // 控制当前展示任务按钮样式 active
      const [active, setActive] = useState("SHOW_ALL");
    
      function addTodo(content) {
        const newData = [].concat(data);
        newData.push({
          id: Date.now(),
          content: content,
          isDone: false,
          dataTime: "2019-10-28"
        });
        setData(newData);
        setInputValue("");
      }
    
      function showStatusList(showStatus) {
        if (showStatus === "SHOW_COMPLETED") {
          const newData = data.filter(item => item.isDone);
          setShowArr([].concat(newData));
          setActive("SHOW_COMPLETED");
        } else if (showStatus === "SHOW_ACTIVE") {
          const newData = data.filter(item => !item.isDone);
          setShowArr([].concat(newData));
          setActive("SHOW_ACTIVE");
        } else {
          setShowArr([].concat(data));
          setActive("SHOW_ALL");
        }
      }
    
      function finishTodo(id) {
        const newData = [].concat(data);
        const index = newData.findIndex(item => item.id === id);
        newData[index].isDone = true;
        setData(newData);
      }
    
      function toggleTodo(id) {
        const newData = [].concat(data);
        const index = newData.findIndex(item => item.id === id);
        newData[index].isDone = !newData[index].isDone;
        setData(newData);
      }
    
      function deleteTodo(id) {
        const newData = [].concat(data);
        const index = newData.findIndex(item => item.id === id);
        newData.splice(index, 1);
        setData(newData);
      }
    
      function todoHeader() {
        return (
          <div className={"mainHeader"}>
            任务列表
            <div className="mainHandle">
              <Button
                size="small"
                type="default"
                className={[
                  "classifyBtn",
                  active === "SHOW_ALL" ? "active" : null
                ].join(" ")}
                onClick={() => showStatusList("SHOW_ALL")}
              >
                全部
              </Button>
              <Button
                size="small"
                type="default"
                className={[
                  "classifyBtn",
                  active === "SHOW_COMPLETED" ? "active" : null
                ].join(" ")}
                onClick={() => showStatusList("SHOW_COMPLETED")}
              >
                已完成
              </Button>
              <Button
                size="small"
                type="default"
                className={[
                  "classifyBtn",
                  active === "SHOW_ACTIVE" ? "active" : null
                ].join(" ")}
                onClick={() => showStatusList("SHOW_ACTIVE")}
              >
                未完成
              </Button>
            </div>
          </div>
        );
      }
    
      return (
        <div className="todoList">
          <div className="todoHeader">
            <h1 className="card-title">React Hooks Todo</h1>
            <span className="card-subtitle">添加任务,管理每日计划</span>
          </div>
          <div className="todoSearch">
            <Search
              placeholder="今天完成什么计划?"
              enterButton="添加任务"
              size="default"
              value={inputValue}
              onChange={e => setInputValue(e.target.value)}
              onSearch={(content, event) => addTodo(content, event)}
            />
          </div>
          <div className="todoMain">
            <List
              header={todoHeader()}
              footer={
                <div className={"mainFooter"}>共 {showArr.length} 项任务</div>
              }
              bordered
              dataSource={showArr}
              renderItem={item => (
                <List.Item>
                  <Button
                    size="small"
                    type={item.isDone ? "primary" : "danger"}
                    className="status"
                  >
                    {item.isDone ? "完成" : "未完成"}
                  </Button>
                  <p className="content">{item.content}</p>
                  <div className="operate">
                    {/* <span>{item.dataTime}</span> */}
                    {item.isDone ? (
                      ""
                    ) : (
                      <Icon
                        type="check-square"
                        style={{ color: "green" }}
                        onClick={() => finishTodo(item.id)}
                      />
                    )}
                    <Icon
                      type="retweet"
                      style={{ color: "#E7AF62" }}
                      onClick={() => toggleTodo(item.id)}
                    />
                    <Icon
                      type="close"
                      style={{ color: "red" }}
                      onClick={() => deleteTodo(item.id)}
                    />
                  </div>
                </List.Item>
              )}
            />
          </div>
        </div>
      );
    }
    
    
    index.js
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.less';
    import TodoList from './TodoList';
    
    ReactDOM.render(<TodoList />, document.getElementById('root'));
    
    index.less
    .todoHeader {
      width: 100%;
      height: 200px;
      background: #eee;
      position: relative;
      text-align: center;
      .card-title {
        padding: 50px 0 30px 0; 
        margin: 0;
        font-size: 44px;
      }
      .card-subtitle {
        color: #666;
        font-size: 14px;
      }
    }
    .todoSearch {
      width: 100%;
      padding: 20px 25%;
    }
    .todoMain {
      width: 100%;
      padding: 0 15%;
      border-color: #1890ff;
      .mainHeader {
        .mainHandle {
          float: right;
          button {
            margin: 0 5px;
          }
          .active {
            background: #96D196;
            border-color: #96D196;
            color: #fff;
          }
        }
      }
      .ant-list {
        border-color: #1890ff;
        .ant-list-header {
          color: #fff;
          background-color: #1890ff;
          font-size: 16px;
        }
        .ant-list-item {
          display: flex;
          .status {
            flex: 1;
          }
          .content {
            flex: 9;
            padding-left: 5px;
            margin: 0;
          }
          .operate {
            flex: 4;
            text-align: right;
            i {
              padding-left: 5px;
              cursor: pointer;
            }
          }
        }
        .ant-list-footer {
          background: #eee;
          .mainFooter {
            text-align: right;
          }
        }
      }
    }
    
    

    相关文章

      网友评论

          本文标题:使用 React Hooks + mock + antd构建一

          本文链接:https://www.haomeiwen.com/subject/enbtgctx.html