关于前端开发过程中虚拟滚动表格表头自定义筛选功能实现方案

137 阅读2分钟

在前端开发过程中(以React+Ant Design+虚拟滚动技术栈为例),开发者经常会遇到表格展示大量数据时的性能问题。虽然初始渲染或动态切换时出现的页面卡顿可以通过分页机制解决,但在某些必须展示全量数据的场景下,虚拟滚动技术就成为了必备方案。然而当表格需要支持表头筛选功能(包括搜索、枚举单选/多选、排序、自定义筛选等)时,传统的虚拟滚动方案往往无法满足需求。


1. 实现难点分析

现有技术方案的局限性

  • 目前网络上关于虚拟滚动结合自定义筛选功能的实践案例相对匮乏。以Ant Design结合react-window的实现为例,这些案例大多仅展示基础的数据呈现功能。当需要实现复杂的表格筛选交互时,开发者往往面临较大挑战。即使对Ant Design Table API非常熟悉的开发人员,实现起来也相当繁琐。

2. 技术实现方案

基于React 17+Ant Design 4.22+ali-react-table 2.6的技术栈实现:

  • 本方案通过Ant Design Table的基础架构,结合ali-react-table提供的组件和API,实现了虚拟滚动与筛选功能的完美结合:

    1. 基础配置兼容性:完全遵循Ant Design Table的columns和dataSource配置规范
    2. 核心筛选功能实现:重点实现了搜索功能,以下是关键代码(usePageCalc.tsx)实现:
    import { SearchOutlined } from '@ant-design/icons';
    import { Button, Input, Popconfirm } from 'antd';
    import React, { useMemo, useState } from 'react';
    
    const usePageCalc = () => {
      const inputRef = React.createRef();
      const searchRef = React.createRef();
      const [inputKeys, setInputKeys] = useState(['']);
      const [searchKeys, setSearchKeys] = useState('');
      const columns = [
        {
          title: (
            <div className="ant-table-filter-column">
              <span className="ant-table-column-title">名称</span>
              <span
                role="button"
                className="ant-dropdown-trigger ant-table-filter-trigger"
                style={{ margin: 0 }}
                onClick={() => setTimeout(() => inputRef.current!.select())}
              >
                <Popconfirm
                  ref={searchRef}
                  placement="bottomRight"
                  overlayClassName="pop-overlay-ProvinceDepthPeakShaving"
                  title={
                    <div style={{ padding: 8 }}>
                      <Input
                        ref={inputRef}
                        placeholder={'搜索名称'}
                        value={inputKeys[0]}
                        onChange={(e) => setInputKeys(e.target.value ? [e.target.value] : [])}
                        onPressEnter={() => {
                          setSearchKeys(inputKeys[0]);
                          // 关闭气泡弹窗
                          searchRef.current!.close();
                        }}
                        style={{ width: 188, marginBottom: 8, display: 'block' }}
                      />
                      <Button
                        type="primary"
                        onClick={() => {
                          setSearchKeys(inputKeys[0]);
                          // 关闭气泡弹窗
                          searchRef.current!.close();
                        }}
                        icon={<SearchOutlined />}
                        size="small"
                        style={{ width: 90, marginRight: 8 }}
                      >
                        搜索
                      </Button>
                      <Button onClick={() => setInputKeys([''])} size="small" style={{ width: 90 }}>
                        重置
                      </Button>
                    </div>
                  }
                >
                  <SearchOutlined style={{ color: '#bfbfbf' }} />
                </Popconfirm>
              </span>
            </div>
          ),
          dataIndex: 'devName',
          fixed: 'left',
          width: 160,
          ellipsis: true,
          rowSpan: 8,
        },
      ];
    
      const dataSource = useMemo(() => {
        const typeSource = [];
        return typeSource.filter((fItem) => (fItem?.devName || '').includes(searchKeys));
      }, [searchKeys]);
    
      return { columns, dataSource };
    };
    
    export default usePageCalc;
    
    

    气泡弹窗样式调整:

    .pop-overlay {
      .ant-popover-arrow,
      .ant-popover-buttons,
      .ant-popover-message-icon {
        display: none;
      }
      .ant-popover-inner-content,
      .ant-popover-message {
        padding: 0;
      }
    }
    

方案总结

本方案的核心在于基于Ant Design Table进行适配改造,通过ali-react-table提供的BaseTable组件及其内置API实现虚拟滚动功能后,再扩展表头搜索功能。该库已内置排序功能实现,其他自定义筛选功能可参考上述搜索功能的实现逻辑。虚拟滚动组件的具体实现可参考ali-react-table官方文档进行实现,如果开发者有更优的实现方案,欢迎在评论区分享交流。