移动端 h5-table react版本支持虚拟列表

news2024/9/24 1:23:40

介绍

适用于 react + ts 的 h5 移动端项目 table 组件

github 链接 :https://github.com/duKD/react-h5-table

有帮助的话 给个小星星

有两种表格组件
常规的:
支持 左侧固定 滑动 每行点击回调 支持 指定列排序 支持滚动加载更多

效果和之前写的vue3 版本类似
vue3 h5 表格

请添加图片描述

大数据量时 使用虚拟列表:
也支持 左侧固定 滑动 每行点击回调 支持 指定列排序 不支持滚动加载

请添加图片描述

开始

npm i @lqcoder/react-h5-table

入口 引入table样式文件

import "@lqcoder/react-h5-table/scripts/style.css";

常规版使用

相关 props 配置 说明

export type tablePropsType<T = any> = {
  rowKey?: string; //表格行 key 的取值字段 默认取id字段
  minTableHeight?: number; //表格最小高度
  showRowNum?: number; // 表格显示几行
  headerHeight?: number; // 头部默认高度
  rowHeight?: number; //每行数据的默认高度
  column: Array<columnItemType<T>>;
  tableData: Array<T>;
  clickOptions?: clickOptions<T>; // 是否需要处理点击事件
  disable?: boolean; // 是否启用下拉加载
  pullDownProps?: pullDownPropsType;
  changePullDownProps?: (args: pullDownPropsType) => void; // 修改加载状态
  handleHeadSortClick?: (propsKey: string, type: sortStatusType) => void;
  onload?: () => void; // 数据加载
  rootValue?: number; //
};



export type columnItemType<T = any> = {
  title: string; // 列名
  dataIndex: string; // table data key 值
  width: number; // 列 宽度
  sortable?: boolean; //是否 支持排序
  align?: "left" | "center" | "right"; // 布局
  render?: (item: T, index?: number) => any; //自定义单元格显示的内容
};

// 下拉加载相关配置
export type pullDownPropsType = {
  error?: boolean; // 数据加载失败
  loading?: boolean; // 数据处于加载状态
  finish?: boolean; // 数据 是否完全加载
  loadingText?: string; // 加载文案
  errorText?: string; // 失败文案
  finishedText?: string; // 完成文案
  offset?: number; //触发加载的底部距离
};

//  点击相关配置
export type clickOptions<T> = {
  clickRender: (item: T, index: number) => React.JSX.Element; // 点击列触发渲染
  clickHeight: number; // 显示栏的高度 
};

代码示例:


// App.tsx 文件
import { useRef, useState } from "react";
import {
  H5Table,
  clickOptions,
  columnItemType,
  sortStatusType,
} from "@lqcoder/react-h5-table";

import Styles from "./App.module.scss";

function App() {
  type dataType = {
    id: number;
    type?: number;
    select: string;
    position: string;
    use: string;
    markValue: string;
    cur: string;
    cost: string;
    newPrice: number;
    float: string;
    profit: string;
    count: string;
  };
  const column: Array<columnItemType<dataType>> = [
    {
      title: "班费/总值",
      width: 250,
      dataIndex: "rateAndSum",
      render(item, _index) {
        return (
          <section className="nameAndMarkValue">
            <div className="name">
              {item.select}
              <span className="type">{item.type === 1 ? "深" : "沪"}</span>
            </div>
            <div className="markValue">
              {item.markValue}=={item.id}
            </div>
          </section>
        );
      },
      align: "left",
    },
    {
      title: "持仓/可用",
      dataIndex: "positionAndUse",
      sortable: true,
      width: 200,
      align: "right",
      render(item, _index) {
        return (
          <section className="positionAndUse">
            <div className="position">{item.position}</div>
            <div className="use">{item.use}</div>
          </section>
        );
      },
    },
    {
      title: "现价/成本",
      dataIndex: "curAndCost",
      sortable: true,
      width: 200,
      align: "right",
      render(item) {
        return (
          <section className="curAndCost">
            <div className="cur">{item.cur}</div>
            <div className="cost">{item.cost}</div>
          </section>
        );
      },
    },
    {
      title: "浮动/盈亏",
      dataIndex: "float",
      width: 200,
      align: "right",
      render(item) {
        return (
          <section className="floatAndProfit">
            <div className="float">{item.float}</div>
            <div className="profit">{item.profit}</div>
          </section>
        );
      },
    },
    {
      title: "账户资产",
      dataIndex: "count",
      width: 200,
    },
  ];

  const temp = Array.from({ length: 20 }).map((item, index) => {
    return {
      id: index,
      select: "三年二班",
      type: 1,
      position: `${27000 + index * 10}`,
      use: "5,000",
      markValue: "500,033.341",
      cur: "30.004",
      cost: "32.453",
      newPrice: 20,
      float: "+18,879.09",
      profit: "-5.45%",
      count: "120,121",
    };
  });

  const dataRef = useRef(temp);

  const [data, setData] = useState(temp);

  const [pullDownProps, setPullDownProps] = useState({
    offset: 10,
    error: false, // 数据加载失败
    loading: false, // 数据处于加载状态
    finish: false, // 数据 是否完全加载
    loadingText: "加载中...", // 加载文案
    errorText: "出错了", // 失败文案
    finishedText: "到底了", // 完成文案
  });

  const onload = () => {
    setTimeout(() => {
      const len = data.length;
      setData(
        data.concat(
          Array.from({ length: 10 }).map((item, index) => {
            return {
              id: len + index,
              select: "三年二班",
              type: 1,
              position: "28000",
              use: "5,000",
              markValue: "500,033.341",
              cur: "30.004",
              cost: "32.453",
              newPrice: 20,
              float: "+18,879.09",
              profit: "-5.45%",
              count: "120,121",
            };
          })
        )
      );
      dataRef.current = dataRef.current.concat(
        Array.from({ length: 10 }).map((item, index) => {
          return {
            id: len + index,
            select: "三年二班",
            type: 1,
            position: "28000",
            use: "5,000",
            markValue: "500,033.341",
            cur: "30.004",
            cost: "32.453",
            newPrice: 20,
            float: "+18,879.09",
            profit: "-5.45%",
            count: "120,121",
          };
        })
      );
      setPullDownProps({
        ...pullDownProps,
        loading: false,
      });
    }, 1000);
  };

  const changePullDownProps = (args: any) => {
    setPullDownProps(args);
  };

  /**
   * 处理排序按钮回调 处理逻辑交给开发
   * @param propsKey 点击的列名
   * @param type 0 默认 1 升 2 降
   * @returns
   */
  const handleHeadSortClick = (propsKey: string, type: sortStatusType) => {
    if (type === 0) {
      setData(dataRef.current);
      return;
    }
    if (propsKey === "positionAndUse") {
      if (type === 1) {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(b.position) - Number(a.position)
        );
        setData(temp);
      } else {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(a.position) - Number(b.position)
        );
        setData(temp);
      }
    }

    if (propsKey === "curAndCost") {
      if (type === 1) {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(b.cur) - Number(a.cur)
        );
        setData(temp);
      } else {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(a.cur) - Number(b.cur)
        );
        setData(temp);
      }
    }
  };

  const handelSell = () => {
    console.log("handelSell----");
  };

  const clickOptions: clickOptions<dataType> = {
    clickRender(item, index) {
      return (
        <section className={Styles["rowDownMark"]}>
          <div className={Styles["rowDownMark-item"]} onClick={handelSell}>
            买入
          </div>
          <div className={Styles["rowDownMark-item"]}>卖出</div>
          <div className={Styles["rowDownMark-item"]}>行情</div>
        </section>
      );
    },
    clickHeight: 60,
  };

  return (
    <>
      <H5Table<dataType>
        disable
        column={column}
        tableData={data}
        onload={onload}
        pullDownProps={pullDownProps}
        changePullDownProps={changePullDownProps}
        handleHeadSortClick={handleHeadSortClick}
        clickOptions={clickOptions}
      ></H5Table>
    </>
  );
}

export default App;

// App.module.scss
.app {
  color: red;
  font-size: 20px;
  .container {
    color: aqua;
  }
}
.rowDownMark {
  width: 100%;
  display: flex;
  height: 60px;
  background-color: #fcfcfc;
  align-items: center;
}
.rowDownMark-item {
  flex-grow: 1;
  color: #309fea;
  text-align: center;
}

大数据量时 使用虚拟列表

相关props 说明

export type virtualTablePropsType<T = any> = {
  rowKey?: string; //表格行 key 的取值字段 默认取id字段
  minTableHeight?: number; //表格最小高度
  showRowNum?: number; // 表格显示几行
  headerHeight?: number; // 头部默认高度
  rowHeight?: number; //每行数据的默认高度
  column: Array<columnItemType<T>>;
  tableData: Array<T>;
  clickOptions?: clickOptions<T>; // 是否需要处理点击事件
  handleHeadSortClick?: (propsKey: string, type: sortStatusType) => void;
  rootValue?: number; //
};

// 0 默认 1 升 2 降
export type sortStatusType = 0 | 1 | 2;

export interface virtualTableInstance {
  scrollIntoView: (index: number) => void;
}

export type columnItemType<T = any> = {
  title: string; // 列名
  dataIndex: string; // table data key 值
  width: number; // 列 宽度
  sortable?: boolean; //是否 支持排序
  align?: "left" | "center" | "right"; // 布局
  render?: (item: T, index?: number) => any; //自定义单元格显示的内容
};

//  点击相关配置
export type clickOptions<T> = {
  clickRender: (item: T, index: number) => React.JSX.Element; // 点击列触发渲染
  clickHeight: number; // 显示栏的高度
};

代码示例:

// App.tsx
import { useRef, useState } from "react";
import {
  H5VirtualTable,
  clickOptions,
  columnItemType,
  sortStatusType,
  virtualTableInstance,
} from "@lqcoder/react-h5-table";

import Styles from "./App.module.scss";

function App() {
  type dataType = {
    id: number;
    type?: number;
    select: string;
    position: string;
    use: string;
    markValue: string;
    cur: string;
    cost: string;
    newPrice: number;
    float: string;
    profit: string;
    count: string;
  };
  const column: Array<columnItemType<dataType>> = [
    {
      title: "班费/总值",
      width: 250,
      dataIndex: "rateAndSum",
      render(item, _index) {
        return (
          <section className="nameAndMarkValue">
            <div className="name">
              {item.select}
              <span className="type">{item.type === 1 ? "深" : "沪"}</span>
            </div>
            <div className="markValue">
              {item.markValue}=={item.id}
            </div>
          </section>
        );
      },
      align: "left",
    },
    {
      title: "持仓/可用",
      dataIndex: "positionAndUse",
      sortable: true,
      width: 200,
      align: "right",
      render(item, _index) {
        return (
          <section className="positionAndUse">
            <div className="position">{item.position}</div>
            <div className="use">{item.use}</div>
          </section>
        );
      },
    },
    {
      title: "现价/成本",
      dataIndex: "curAndCost",
      sortable: true,
      width: 200,
      align: "right",
      render(item) {
        return (
          <section className="curAndCost">
            <div className="cur">{item.cur}</div>
            <div className="cost">{item.cost}</div>
          </section>
        );
      },
    },
    {
      title: "浮动/盈亏",
      dataIndex: "float",
      width: 200,
      align: "right",
      render(item) {
        return (
          <section className="floatAndProfit">
            <div className="float">{item.float}</div>
            <div className="profit">{item.profit}</div>
          </section>
        );
      },
    },
    {
      title: "账户资产",
      dataIndex: "count",
      width: 200,
    },
  ];

  const temp = Array.from({ length: 20000 }).map((item, index) => {
    return {
      id: index,
      select: "三年二班",
      type: 1,
      position: `${27000 + index * 10}`,
      use: "5,000",
      markValue: "500,033.341",
      cur: "30.004",
      cost: "32.453",
      newPrice: 20,
      float: "+18,879.09",
      profit: "-5.45%",
      count: "120,121",
    };
  });

  const dataRef = useRef(temp);
  const tableRef = useRef<virtualTableInstance>();

  const [num, setNum] = useState(1);
  const [data, setData] = useState(temp);

  /**
   * 处理排序按钮回调 处理逻辑交给开发
   * @param propsKey 点击的列名
   * @param type 0 默认 1 升 2 降
   * @returns
   */
  const handleHeadSortClick = (propsKey: string, type: sortStatusType) => {
    if (type === 0) {
      setData(dataRef.current);
      return;
    }
    if (propsKey === "positionAndUse") {
      if (type === 1) {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(b.position) - Number(a.position)
        );
        setData(temp);
      } else {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(a.position) - Number(b.position)
        );
        setData(temp);
      }
    }

    if (propsKey === "curAndCost") {
      if (type === 1) {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(b.cur) - Number(a.cur)
        );
        setData(temp);
      } else {
        const temp = [...dataRef.current].sort(
          (a, b) => Number(a.cur) - Number(b.cur)
        );
        setData(temp);
      }
    }
  };

  const handelSell = () => {
    console.log("handelSell----");
  };

  const clickOptions: clickOptions<dataType> = {
    clickRender(item, index) {
      return (
        <section className={Styles["rowDownMark"]}>
          <div className={Styles["rowDownMark-item"]} onClick={handelSell}>
            买入
          </div>
          <div className={Styles["rowDownMark-item"]}>卖出</div>
          <div className={Styles["rowDownMark-item"]}>行情</div>
        </section>
      );
    },
    clickHeight: 60,
  };
  const scrollTo = () => {
    tableRef.current?.scrollIntoView(num);
  };

  const getValue = (val: any) => {
    setNum(Number(val.target.value) || 0);
  };

  return (
    <>
      <input type="text" onChange={getValue} />
      <button onClick={scrollTo}>跳到</button>
      <H5VirtualTable<dataType>
        disable
        column={column}
        tableData={data}
        handleHeadSortClick={handleHeadSortClick}
        clickOptions={clickOptions}
        ref={tableRef}
      ></H5VirtualTable>
    </>
  );
}

export default App;

// App.module.scss
.app {
  color: red;
  font-size: 20px;
  .container {
    color: aqua;
  }
}
.rowDownMark {
  width: 100%;
  display: flex;
  height: 60px;
  background-color: #fcfcfc;
  align-items: center;
}
.rowDownMark-item {
  flex-grow: 1;
  color: #309fea;
  text-align: center;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1397771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023江苏职教高考计算机技能考试--填空题解析

/*--------------- 【程序填空】 ----------------- 题目&#xff1a;验证任意一个大于1的正整数都可以找到 一串连续奇数&#xff0c;它们的和等于该整数的立方。 例如&#xff1a;4的立方等于64&#xff0c;6413579111315程序运行结果如下&#xff1a;3的立方等于27&#xff…

Vue四个阶段,八个钩子函数

- 创造阶段&#xff1a;创建Vue实例和初始化数据事件&#xff0c;数据代理&#xff0c;监测watch - beforeCreate&#xff0c;只是创建实例&#xff0c;不能this.$el,this.msg,this.方法名&#xff08;&#xff09; - created&#xff0c;数据代理了&#xff0c;能v…

上位机编程:CP56Time2a格式精讲

Cp56Time2a介绍&#xff1a; Cp56Time2a是西门子PLC&#xff08;可编程逻辑控制器&#xff09;中用于时间数据传输的一种特殊格式&#xff0c;主要用于PCS7和基于TCP/IP的S7通信过程中。这种时间格式主要为了确保在不同的系统和设备之间进行精确的时间同步。 Cp56Time2a格式&a…

CodeReview 小工具

大家开发中有没有遇到一个版本开发的非常杂&#xff0c;开发很多个项目&#xff0c;改动几周后甚至已经忘了自己改了些什么&#xff0c;领导要对代码review的时候&#xff0c;理不清楚自己改过的代码&#xff0c;只能将主要改动的大功能过一遍。这样就很容易造成review遗漏&…

力扣日记1.19-【二叉树篇】538. 把二叉搜索树转换为累加树

力扣日记&#xff1a;【二叉树篇】538. 把二叉搜索树转换为累加树 日期&#xff1a;2023.1.19 参考&#xff1a;代码随想录、力扣 ps&#xff1a;因为准备组会汇报又搁置了好久&#xff08;其实就是懒逃避T^T)&#xff0c;但这是最后一道二叉树啦啊啊啊&#xff01;&#xff01…

calloc与realloc和malloc的区别以及new

目录 calloc、realloc 和 malloc 三个函数的区别在于 更详细的示例代码 交叉使用 内存泄漏 悬空指针 内存重叠 new 的语法 使用 new 运算符在堆上创建学生对象的示例 new和malloc都可以用于在堆上分配内存 calloc、realloc 和 malloc 是 C/C 中用于动态内存分配的函…

PrestaShop购物系统 SQL注入漏洞复现(CVE-2023-30150)

0x01 产品简介 PrestaShop 是一个功能丰富,基于 PHP5 开发的 Web2.0 网上购物系统。PrestaShop 具有可定制,稳定等特点。整个系统只有 5.8MB,易于快速安装。 0x02 漏洞概述 PrestaShop 的部分主题中使用Leo Custom Ajax模块拓展,Leo Custom Ajax模块中可以在/modules/le…

ValueError: Unable to read workbook: could not read strings from data.xlsx解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

RNN:Long Short-term Memory(中)

目录 1 LSTM 的简图 2 LSTM 的整体结构 2.1 结构图 2.2 流程图 3 举个例子 3.1 简单看看 3.2 代入 LSTM 4 Original Network v.s. LSTM 5 细看 LSTM 原视频&#xff1a;李宏毅 2020&#xff1a;Recurrent Neural Network (Part I) 1 LSTM 的简图 LSTM 实际…

css3+javaScript实现一个左右钟摆-摇晃的红灯笼网页特效

css3javaScript实现一个左右钟摆-摇晃的红灯笼网页特效&#xff01;前天逛博客时无意中看见了&#xff0c;别人的博客顶部有一个会左右钟摆的摇晃的红灯笼&#xff0c;产生了想法&#xff0c;我也想给自己做一个&#xff0c;但是网上找了很多方案&#xff0c;都没有实现。终于在…

教您如何下载保存钉钉视频到电脑本地

教您如何下载保存钉钉视频到电脑和手机相册地瓜网络技术 大家好&#xff0c;我们这边是地瓜网络技术&#xff01;30秒教会你下载钉钉视频&#xff01;现在很多群管理员把视频设置为禁止下载&#xff0c;导致我们无法正常的下载群直播回放视频&#xff0c; 今天我们就教大家如何…

第十二篇【传奇开心果系列】Ant Design Mobile of React开发移动应用:内置组件实现酷炫CSS 动画

Ant Design Mobile of React 开发移动应用示例博文系列 第一篇【传奇开心果系列】Ant Design Mobile of React 开发移动应用:从helloworld开始 第二篇【传奇开心果系列】Ant Design Mobile of React 开发移动应用:天气应用 第三篇【传奇开心果系列】Ant Design Mobile of Reac…

flutter获取地理定位:geolocator依赖详细用法

本文使用geolocator插件实现app物理定位功能。 该插件的主要功能有&#xff1a; 获取最后已知位置&#xff1b;获取设备当前位置&#xff1b;获取连续的位置更新&#xff1b;检查设备是否启用了定位服务&#xff1b;计算两个地理坐标之间的距离&#xff08;米&#xff09;&am…

linux网络协议栈2--网络包接收发送流程

上文我们讲了报文格式&#xff0c;应该对数据传输格式有了一定了解&#xff0c;这篇文章主要讲述的是网络包接收和发送的流程&#xff0c;主要是大方面来介绍。 网络包接收流程 当网络数据帧通过网络传输到达网卡时&#xff0c;网卡会将网络数据帧通过DMA的方式放到环形缓冲区…

Flutter轮播图Banner

使用插件&#xff1a;flutter_swiper 实现轮播图 pubspec.yaml 增加 &#xff1a;flutter_swiper : ^lastest_version 在项目文件夹下打开命令行执行&#xff1a;flutter packages get 安装插件 home_page.dart中使用swiper 程序运行:先启动虚拟设备后&#xff0c;执行命令f…

【C语言】linux内核ipoib模块 - ipoib_send

一、ipoib_send函数定义 int ipoib_send(struct net_device *dev, struct sk_buff *skb,struct ib_ah *address, u32 dqpn) {struct ipoib_dev_priv *priv ipoib_priv(dev);struct ipoib_tx_buf *tx_req;int hlen, rc;void *phead;unsigned int usable_sge priv->max_sen…

redis数据安全(一)数据持久化

一、Redis数据安全措施: 1、将数据持久化至硬盘 2、将数据复制至其他机器&#xff1b; 复制是在数据持久化的基础上进行的。 二、将数据持久化至硬盘 1、介绍&#xff1a;Redis是一个基于内存的数据库&#xff0c;它的数据是存放在内存中&#xff0c;内存有个问题就是关闭…

大模型 RAG 面试篇

1.LLMs 存在模型幻觉问题&#xff0c;请问如何处理&#xff1f; 检索LLM。 先用问题在领域数据库里检索到候选答案&#xff0c;再用LLM对答案进行加工。 2.基于LLM向量库的文档对话 思路是怎么样&#xff1f; 加载文件读取文本文本分割文本向量化问句向量化在文本向量中匹配…

构建高效外卖系统:技术实践与代码示例

外卖系统在现代社会中扮演着重要的角色&#xff0c;为用户提供了便捷的用餐解决方案。在这篇文章中&#xff0c;我们将探讨构建高效外卖系统的技术实践&#xff0c;同时提供一些基础的代码示例&#xff0c;帮助开发者更好地理解和应用这些技术。 1. 技术栈选择 构建外卖系统…

Python爬虫从入门到入狱系列合集

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…