• react antdesign table 添加滚动加载(下拉翻页功能)


    1. 逻辑功能简单介绍

    1. 逻辑并不复杂,首先获取到表格中可滚动那一级dom元素,然后监听它的滚动;当滚动到底了则触发我们自己的函数;
    2. 全篇幅最主要的一点就是 useEffect 中的内容,其他的都是看你怎么来了;
    3. useEffect 内容简单介绍:
      (1)findNeedNode 函数: 递归查找 Table 元素中 className 为 ant-table-body 的节点(可滚动那一级dom元素)
      (2)找到元素后添加监听滚动;
      (3)判断屏幕高度和滚动条的高度,达到条件后则触发父级传入过来的滚动函数;
      (4)功能拓展:实现了 findNeedNode 函数,其实就相当于实现了在ui框架组件内查找任意首次出现的 className。这里举个例子,比如说在 Table 中实现定位到某条内容;改装 findNeedNode函数,固定查找 ant-table-body className 修改为可传入式;定位到某条内容需要获取到这条内容的所在盒子的高度,而表格内部内容不可控,所以说需要获取表格内所有内容的高度进行加法运算(此处运算到需要定位的内容就停止),得到高度后,获取到 Table 中 tr 上一级的节点,设置这个节点的 scrollTop 属性进行定位。
    4. 注意如果想要出现滚动条需要设置 scroll 属性 给如 父级的高度就行了(document.getElementById(‘tableFather’)?.clientHeight)
    5. 如果介意代码野的可以看看总结的第三点和第四点
    6. 这块个人建议别看了,因为这块没有虚拟列表的优化,页面卡顿得厉害;去看看我虚拟列表实现吧
    7. React之antdesign官网虚拟列表二次封装(涵盖虚拟列表滚动加载)

    2. 实现

    import { useState, useEffect, useRef } from 'react';
    import { Table } from 'antd'
    const defaultTableInfo = {
      loading: false,
      tableData: [],
      tableConfig: [
    	{
          title: '名字',
          dataIndex: 'name',
          width: '180px',
          align: 'center',
          render: (text, record, index) => text
        },
      ],
      pagination: {
        pageNum: 1,
        pageSize: 10,
        total: 0
      }
    }
    const renderNumber = 0;
    const Table = (props) => {
      const { scroll, tableInfo = defaultTableInfo, onScrollBottom } = props;
      const [pagination, setPagination] = useState(tableInfo.pagination);
      const [columns, setColumns] = useState<any>(tableInfo.tableConfig);
    
      const tableRef = useRef<any>(null)
      useEffect(() => {
        if (tableInfo.loading) return;
        // 获取可滚动节点的父级节点
        const findNeedNode: any = (node: any) => {
          // 这个判断逻辑是看界面节点找到的可滚动那一级
          if (node.className === 'ant-table-body') return node;
          if (node.children) {
          	// 这块内容可以理解为数组中的map操作 return [].map(v=>xxxx);为啥不用map的原因是needNode不是一个真正的数组;
            let needNode: any = [];
            node.children.forEach((child: any) => {
              needNode.push(findNeedNode(child))
            })
            return needNode;
          }
        }
        setTimeout(() => {
       	  // 最终处理完成的数据不知道在多少维;就当是N维数组;以flat(Infinity)降维处理;
          const dom = findNeedNode(tableRef.current).flat(Infinity)[0];
          // 
          if (!dom) return;
          // 监听 屏幕是否到底了;
          if (renderNumber > 1) return;
          // 加载数据完毕后 只渲染第一次(addEventListener只让他生效一次!!!)
          renderNumber++;
          dom.addEventListener("scroll", () => {
            const { pageSize, pageNum, total } = tableInfo.pagination;
            const all = pageSize * pageNum;
            const scrollTop = dom.scrollTop;
            // 变量windowHeight是可视区的高度
            const windowHeight = dom.clientHeight || dom.clientHeight;
            // 变量scrollHeight是滚动条的总高度
            const scrollHeight = dom.scrollHeight || dom.scrollHeight;
            if (scrollTop + windowHeight + 1 > scrollHeight) {
              if (all < total) {
                // 表格置空不能有滚动加载
                if (tableInfo.tableData.length < 1) return;
                // 触发到底的函数
                onScrollBottom({ ...pagination, pageNum: pageNum + 1 });
              }
            }
          });
        }, 0);
      }, [tableInfo.loading])
      return <Table
                size="small"
                rowKey="uuid"
                ref={tableRef}
                loading={tableInfo.loading}
                pagination={false}
                scroll={scrollInner}
                columns={columns.filter((item: any) => !item.hidden)}
                dataSource={tableInfo.tableData}
              />
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    3. 功能拓展

    1. findNeedNode 功能拓展:可查找ui框架内任意首次出现的className节点(温馨提示:此递归也可改成查找任意出现过的className)
    const findNeedNode: any = (node: any, key: string = 'ant-table-body') => {
      if (node.className === key) return node;
      if (node.children) {
        let needNode: any = [];
        node.children.forEach((child: any) => {
          needNode.push(findNeedNode(child, key))
        })
        return needNode;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 定位功能可自己实现(有问题可以在评论区询问);

    总结

    1. 上面代码是目测的,应该没有具体问题,反正中心点跟着我的介绍走,然后参考上面的示例,一般不会出啥问题。
    2. 如果有其他方法可以一起探讨一下!
    3. 上面这个因为使用了 addEventListener 所以说会有一个蛇皮问题,此组件如果有任何更新操作会导致整个组件重新渲染(别担心,正常一两三四五个表格在同一个页面根本看不出来,只是这个操作感觉很野的感觉),因为 react 是在全局的 document 上做的事件处理,我这个操作算是破坏这个流程的感觉,这块我倒是不知道咋个解决了,有大佬知道的求告知。
    4. 第三点的问题综合起来就是:在ui库里面的某个元素添加节点事件监听(addEventListener)后会出现的问题;
  • 相关阅读:
    ES6之Symbol和Symbol属性
    C语言指针重点
    阴影进阶,实现更加的立体的阴影效果!
    安全开发实战(2)---域名反查IP
    动物实验,如何设置对照?
    【数组的使用】
    Linux 的交换空间(swap)是什么?有什么用?
    IDEA中为Maven配置使用vpn工具连接的网络
    STL容器简述(c++)
    基于Python开发的五子棋小游戏(源码+可执行程序exe文件+程序配置说明书+程序使用说明书)
  • 原文地址:https://blog.csdn.net/weixin_47436633/article/details/126594728