react 实现一个简单的excel表格(可以改变宽度、实时输入、select *ui自行优化,思路可以参考)

25 篇文章 0 订阅

首先看效果:
在这里插入图片描述

1、首先就是主要代码 index.tsx

import { FC, useEffect, useRef, useState } from "react";
import columns, { columnsType } from "./config";
import { Input } from "antd";

import "./style.less";
//是不是拖拽情况
let isMouseWidth: boolean = false;
//相同class的集合
let classNameArr: any[] = [];

const Table: FC = () => {
  const [list, setList] = useState<any[]>([]);
  let realDom: HTMLElement | null | any;
  let line: any = document.getElementById("line");

  useEffect(() => {
    let arr = new Array();
    for (let i = 0; i < 50; i++) {
      let obj = {};
      for (let j = 0; j < 10; j++) {
        obj = { ...obj, [`title${j}`]: `${i}-${j}` };
      }
      arr = [...arr, obj];
    }
    setList(arr);
  }, []);
  //鼠标移动
  window.onmousemove = (e) => {
    if (!isMouseWidth) {
      return;
    }
    try {
      line.style.display = "block ";
      line.style.left = `${e.clientX}px `;
    } catch (e) {}
  };

  //鼠标抬起
  window.onmouseup = (e) => {
    if (isMouseWidth == false) {
      return;
    }
    try {
      //保留最少10px的宽度
      if (e.clientX - realDom.offsetLeft < 10) {
        return;
      }
      line.style.display = "none";
      realDom.style.width = `${e.clientX - realDom.offsetLeft}px `;
      classNameArr.forEach((ele, index) => {
        ele.style.width = `${e.clientX - realDom.offsetLeft}px `;
      });
      //鼠标准备移动时,全局文字不可选中
      document.onselectstart = function () {
        return true;
      };
    } catch (e) {}
    isMouseWidth = false;
  };
  //返回相同class的元素
  const getElementsByClassName = (className: any) => {
    let d = document;
    let children = d.getElementsByTagName("*") || document.all; //获取页面所有元素
    let elements = new Array(); //定义一个数组,用于存储所得到的元素
    //获取元素的class为className的所有元素
    for (let i = 0; i < children.length; i++) {
      let child = children[i];
      let classNames = child.className.split(" ");
      for (let j = 0; j < classNames.length; j++) {
        if (classNames[j] == className) {
          elements.push(child); //如果class存在,则存入elements
          break;
        }
      }
    }
    return elements;
  };
  //一个整体的表
  const getList = () => {
    return (
      <>
        {list.map((ele, index) => {
          return (
            <div className="list" key={index}>
              {getItem(ele, index)}
            </div>
          );
        })}
      </>
    );
  };

  //一条数据
  const getItem = (itemObj: any, indexObj: number) => {
    let Arr: any[] = [];
    for (let ele in itemObj) {
      columns().forEach((element: columnsType, index: number) => {
        if (element.dataIndex == ele) {
          Arr = [
            ...Arr,
            {
              text: itemObj[ele],
              valueType: element.valueType,
              key: element.key,
            },
          ];
          return;
        }
      });
    }
    return (
      <>
        {Arr.map((ele: any, index: number) => {
          return <>{getBox(ele, indexObj)}</>;
        })}
      </>
    );
  };

  //一个格子
  const getBox = (ele: any, indexObj: number) => {
    //input  输入的值处理
    const handleInputOnChange = (e: any) => {
      list[indexObj][ele.key] = e.target.value;
      let copy = JSON.parse(JSON.stringify(list));
      setList(copy);
    };
    //input  输入的值处理
    const handleSelectOnChange = (e: any) => {
      list[indexObj][ele.key] = e.target.value;
      let copy = JSON.parse(JSON.stringify(list));
      setList(copy);
    };
    return (
      <>
        {ele.key != "title4" ? (
          <input
            className={`${ele.key} input`}
            value={ele.text}
            onChange={handleInputOnChange}
          />
        ) : (
          <select
            className={`${ele.key} select`}
            value={ele.text}
            onChange={handleSelectOnChange}
          >
            <option>123</option>
            <option>124</option>
            <option>125</option>
          </select>
        )}
      </>
    );
  };

  return (
    <>
    <div className="table">
    <div className="header" key="header">
        {columns().map((ele, index) => {
          return (
            <>
              <div className="title" id={ele.key}>
                {ele.title}{" "}
                <div
                  className="mouseWidth"
                  onMouseDown={(e) => {
                    console.log("鼠标按下");
                    isMouseWidth = true;
                    classNameArr = getElementsByClassName(ele.key);
                    realDom = document.getElementById(ele.key);
                    //鼠标准备移动时,全局文字不可选中
                    document.onselectstart = function () {
                      return false;
                    };
                  }}
                  onMouseUp={(e) => {
                    console.log("鼠标已经移除");
                    isMouseWidth = false;
                     
                  }}
                ></div>
              </div>
            </>
          );
        })}
      </div>
      {getList()}
      <div className="line" id="line"></div>
    </div>
  
    </>
  );
};

export default Table;

2、配置文件 config.ts

const columns = () => {
    let arr: columnsType[] = [
        {
            title: 'title0',
            dataIndex: 'title0',
            key: 'title0',
        }, {
            title: 'title1',
            dataIndex: 'title1',
            key: 'title1',
        }, {
            title: 'title2',
            dataIndex: 'title2',
            key: 'title2',
        }, {
            title: 'title3',
            dataIndex: 'title3',
            key: 'title3',
        }, {
            title: 'title4',
            dataIndex: 'title4',
            key: 'title4',
        }, {
            title: 'title5',
            dataIndex: 'title5',
            key: 'title5',
        }, {
            title: 'title6',
            dataIndex: 'title6',
            key: 'title6',
        }, {
            title: 'title7',
            dataIndex: 'title7',
            key: 'title7',
        }, {
            title: 'title8',
            dataIndex: 'title8',
            key: 'title8',
        }, {
            title: 'title9',
            dataIndex: 'title9',
            key: 'title9',
        },
    ]
    return arr
}


export type columnsType = {
    title: string,
    dataIndex: string,
    key: string,
    hideInTable?: boolean,
    hideSearch?: boolean,
    valueType?: string
}
export default columns

3、最后补上样式 style.less

.header {
    display: flex;
    position: relative;
    height: 25px;
    .title {
        width: 100px;
        border: 1px solid #ccc;
        position: relative;
        overflow: hidden;
    }
}
.list {
    display: flex;
    .item {
        .box {}
    }
}
.select {
    width: 100px;
    height: 20px;
    border: 1px solid #ccc;


}
.input {
    width: 100px;
    border: 1px solid #ccc;
    height: 20px;
    text-align: center;
    overflow: hidden;
}
.mouseWidth {
    position: absolute;
    // border: solid 1px red;  
    // background-color: #ccc;
    width: 10px;
    height: 23px;
    top: 0px;
    right: -5px;
    cursor: col-resize
}
.line{
    position: absolute;
    left: 50px;
    top: 0px;
    height: 100%;
    z-index: 2;
    width: 1px;
    background-color: blue;
    display: none;
}
.table{
    // overflow: scroll;
    // width: 150%;
    // height: 60%;
    // position: absolute;
}
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值