React hooks+typescript+Antd 练习+简易回收站 适合前端小白学习之后练手的小案例

React hooks+typescript+Antd 简易回收站

最近学习阶段,自己写了一个小练习巩固基础,代码有少量注释,写的不好勿喷

示例 运行结果如下
在这里插入图片描述在这里插入图片描述因为是自己做练习,所以文件都写在一个目录里面
目录结构如下

在这里插入图片描述
index.tsx的代码

import React from 'react'
import { Tabs, Card } from 'antd';
import { observer } from 'mobx-react'
import './index.css'
import First from './First'
import Second from './second';
const Recycle = observer(() => {
    const { TabPane } = Tabs;
    function callback(key: any) {
        // console.log(key);
    }
    return (
        <>
            <Card>
                <Tabs defaultActiveKey="1" onChange={callback}>
                    <TabPane tab="文件" key="1">
                        <First />
                    </TabPane>
                    <TabPane tab="回收站" key="2">
                        <Second/>
                    </TabPane>
                </Tabs>
            </Card>
        </>
    )
})
export default Recycle

FirstStore.ts代码

import React from 'react'
import { observable, action } from 'mobx'
export interface FristOption {
  key?: number,
  name: string,
  size?: string,
  type?: string,
  person?: string,
  time?: string,
}
class FirstStore {
  @observable datas: any[] = [];
  //回收站数据
  @observable Tdatas: any[] = [];
  //获取格式化时间
  @action getNowDate = () => {
    const date = new Date();
    let month: string | number = date.getMonth() + 1;
    let strDate: string | number = date.getDate();
    let Hours: string | number = date.getHours()
    let Minutes: string | number = date.getMinutes()
    let Seconds: string | number = date.getSeconds()
    if (month <= 9) {
      month = "0" + month;
    }
    if (strDate <= 9) {
      strDate = "0" + strDate;
    }
    if (Hours <= 9) {
      Hours = "0" + Hours;
    }
    if (Minutes <= 9) {
      Minutes = "0" + Minutes;
    }
    if (Seconds <= 9) {
      Seconds = "0" + Seconds;
    }
    return date.getFullYear() + "-" + month + "-" + strDate + " "
      + Hours + ":" + Minutes + ":" + Seconds;
  }
  //上传文件,恢复文件
  @action addData(item:any) {
    const newData = this.datas;
    console.log(item.size);
    //文件类型修改
    let index = item.name.lastIndexOf('\.')
    let Type = item.name.substring(index+1, item.name.length);
   //保存要添加的数据
    const saveData: FristOption = ({
      key: this.datas.length,
      name: item.name,
      size: item.size,
      type: Type,
      person: "111",
      time: this.getNowDate(),
    })
    newData.splice(this.datas.length+1, 0, saveData)
    this.datas = [...newData]   
  }

  //删除文件
  @action delData(item: any) {
     //添加回收站数据
     if (item) {
      const newitem = this.Tdatas.slice();
      newitem.push({
        key: this.Tdatas.length,
        name: item.name,
        size: item.size,
        type: item.type,
        person: item.person,
        time: this.getNowDate(),
      })
      this.Tdatas = [...newitem]
    }
    //删除
    const newData = this.datas.slice();
    let i = newData.findIndex((datas) => datas.name === item.name);
    newData.splice(i,1)
    this.datas=[...newData]
  }

  //回收站删除文件
  @action delTData(item: any) {
    const newData = this.Tdatas.slice();
    let i = newData.findIndex((datas) => datas.name === item.name);
    newData.splice(i, 1)
    this.Tdatas = [...newData]  
  }

}
export default React.createContext(new FirstStore())

First.tsx代码

import React, { useState, useContext } from 'react'
import { Table, Button, message, Upload, Tooltip } from 'antd';
import { observer } from 'mobx-react'
import Store from './FirstStore'
import { DeleteOutlined, UploadOutlined } from "@ant-design/icons"
import { toJS } from 'mobx';
//import './index.css'
const First = observer(() => {
    const store = useContext(Store)
    const [RowItems, setRowItems] = useState([])
    const columns:any = [
        {
            title: '名称',
            dataIndex: 'name',
            sorter: (a: any, b: any) => a.size - b.size,
            //文字超过显示...鼠标悬停显示内容
            onCell: () => {
                return {
                    style: {
                        maxWidth: 150,
                        overflow: "hidden",
                        whiteSpace: "nowrap",
                        textOverflow: "ellipsis",
                        cursor: "pointer"
                    }
                }
            },
            render: (text: any) => <Tooltip placement="topLeft" title={text}>{text}</Tooltip>
        },
        {
            title: '大小',
            dataIndex: 'size',
            defaultSortOrder: 'descend',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '类型',
            dataIndex: 'type',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '操作者',
            dataIndex: 'person',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '更新时间',
            dataIndex: 'time',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '操作',
            dataIndex: "work",
            // 生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引
            render: (x: any, item: any, index: number) => <DeleteOutlined onClick={() => Deleteicon(item, index)} />
        },
    ];
    const Deleteicon = (item: any, index: number) => {
        store.delData(item)
    }
    //复选框
    const rowSelection = {
        onChange: (selectedRowKeys: any, selectedRows: any) => {
            if (selectedRows) {
                setRowItems(selectedRows)
            }

        }
    };
    //多个删除
    const DeleteAll = () => {
        if (RowItems) {
            for (let i = 0; i < RowItems.length; i++) {
                store.delData(RowItems[i])
            }
        }
    }

    //上传
    const fileChange = (info: any) => {
        if (info.file.status !== 'uploading') {
            // console.log(info.file, info.fileList);
        }
        if (info.file.status === 'done') {
            //成功
            //文件大小

            if (info.file.size < 1024) {
                info.file.size = info.file.size + 'B';
            } else if (info.file.size < (1024 * 1024)) {
                info.file.size = (info.file.size / 1024).toFixed(2) + 'KB';
            } else if (info.file.size < (1024 * 1024 * 1024)) {
                info.file.size = (info.file.size / (1024 * 1024)).toFixed(2) + 'MB';
            }
            else {
                info.file.size = (info.file.size / (1024 * 1024 * 1024)).toFixed(2) + 'GB';
            }
            store.addData(info.file)
            //  message.success(`${info.file.name} 上传成功`);
        } else if (info.file.status === 'error') {
            message.error(`${info.file.name} .`);
        }
    }
    return (
        <>
            <div>
                <div style={{ marginBottom: 16 }}>
                </div>
                <Button type="primary" style={{ float: "left", marginBottom: 5, marginRight: 5 }} onClick={DeleteAll}>
                    批量删除
            </Button>
                <div style={{ display: "flex", float: "left", marginBottom: 5 }}>
                    <Upload
                        name="file"
                        action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
                        onChange={fileChange}
                        showUploadList={false}
                    >
                        <Button icon={<UploadOutlined />} >上传</Button>
                    </Upload>,
     </div>
                <Table
                    rowSelection={rowSelection}
                    columns={columns}
                    dataSource={store?.datas}
                    showSorterTooltip={false}
                />
            </div>
        </>
    )
})
export default First

second.tsx代码

import React, { useState, useContext } from 'react'
import { Table, Menu, Dropdown, Button, Tooltip } from 'antd';
import { observer } from 'mobx-react'
import Store, { FristOption } from './FirstStore'
import { SettingFilled } from "@ant-design/icons"
import { toJS } from 'mobx';
//import './index.css'
const Second = observer(() => {
    const store = useContext(Store)
    const [RowItems, setRowItems] = useState([])//保存批量选中时的行元素,是一个数组
    const [showMenu, setShowMenu] = useState(false)//控制下拉菜单的显示隐藏
    const [recoveritem, setRecoveritem] = useState()//保存回收站点击设置图标传来的行数据
    const [Recoverindex, setRecoverindex] = useState()//保存回收站点击设置图标传来的行索引
    //回收站设置下拉菜单
    const menu = (
        <Menu style={{ display: showMenu ? "block" : "none" }}>
            <Menu.Item onClick={() => { Recover(recoveritem, Recoverindex) }}>
                <a target="_blank" rel="noopener noreferrer" >恢复文件</a>
            </Menu.Item >
            <Menu.Item danger onClick={() => { Delete(recoveritem, Recoverindex) }}>彻底删除</Menu.Item>
        </Menu>
    );
    //回收站恢复文件
    const Recover = (item: any, index: any) => {
        store.addData(item)
        store.delTData(item)
    }
    //回收站删除文件
    const Delete = (item: any, index: any) => {
        store.delTData(item)
    }
    //回收站点击设置图标
    const Deleteicon = (item: any, index: any) => {
        setRecoveritem(item)
        setRecoverindex(index)
        setShowMenu(!showMenu)
    }
    const rowSelection = {
        onChange: (selectedRowKeys: any, selectedRows: any) => {
            if (selectedRows) {
                setRowItems(selectedRows)
            }

        }
    };
    //批量恢复
    const RecoverAll = () => {
        if (RowItems) {
            for (let i = 0; i < RowItems.length; i++) {
                store.addData(RowItems[i])
                store.delTData(RowItems[i])
            }
        }
    }
    //批量删除
    const delRecoverAll = () => {
        store.Tdatas = []
    }
    const columns :(any)=[
        {
            title: '名称',
            dataIndex: 'name',
            sorter: (a: any, b: any) => a.size - b.size,
             //文字超过显示...鼠标悬停显示内容
             onCell: () => {
                return {
                    style: {
                        maxWidth: 150,
                        overflow: "hidden",
                        whiteSpace: "nowrap",
                        textOverflow: "ellipsis",
                        cursor: "pointer"
                    }
                }
            },
            render: (text: any) => <Tooltip placement="topLeft" title={text}>{text}</Tooltip>
        },
        {
            title: '大小',
            dataIndex: 'size',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '类型',
            dataIndex: 'type',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '操作者',
            dataIndex: 'person',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '删除时间',
            dataIndex: 'time',
            sorter: (a: any, b: any) => a.size - b.size,
        },
        {
            title: '操作',
            dataIndex: "work",
            render: (x: any, item: any, index: any) =>
                <Dropdown overlay={menu}>
                    <a className="ant-dropdown-link">
                        <SettingFilled
                            onClick={() => { Deleteicon(item, index) }} />
                    </a>
                </Dropdown>
        },
    ];
    return (
        <>
            <div>
                <div style={{ marginBottom: 16 }}>
                </div>
                <Button type="primary" style={{ float: "left", marginBottom: 5, marginRight: 5 }} onClick={RecoverAll}>
                    批量恢复
            </Button>
                <Button style={{ float: "left", marginBottom: 5, marginRight: 5 }} onClick={delRecoverAll}>
                    清空回收站
            </Button>
                <Table
                    rowSelection={rowSelection}
                    columns={columns}
                    dataSource={store.Tdatas}
                />
            </div>
        </>
    )
})
export default Second

样式布局基本上都是Antd中的,index.css一开始创建了没用上,最后在App.tsx中引用index.tsx组件< Recycle/>就可以运行了。

(有错误请留言哦,互相学习)

附:Antd官网

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值