基于React和Ant Design的动态搜索表单与数据表格组件实践教程

350 阅读4分钟

一、引言

在Web应用开发过程中,搜索功能是提升用户体验的重要环节。本文将带领大家使用React和Ant Design库,构建一个动态搜索表单与数据表格组件。通过本文,您将学习到如何实现表单的动态渲染、数据表格的分页加载以及与后端服务的交互。

二、主要技术栈

  • React:用于构建用户界面的JavaScript库。
  • TypeScript:为JavaScript提供类型支持,提高代码可维护性。
  • Ant Design:一套企业级的UI设计语言和React组件库。
  • Axios:基于Promise的HTTP客户端,用于与后端服务进行数据交互。
  • Moment.js:处理日期时间的JavaScript库。

三、组件设计

  1. 接口定义 首先,我们定义两个接口和一个类型,用于描述搜索表单项和数据表格列的结构:
export interface SearchFormItem {
  name: string;
  label: string;
  type: 'input' | 'select' | 'datePicker';
  options?: { label: string; value: string; }[];
}
type TableColumn = {
  title: string;
  dataIndex: string;
  key: string;
};
interface SearchFormTableProps {
  searchItems: SearchFormItem[];
  tableColumns: TableColumn[];
  fetchDataUrl: string;
}
  1. 组件实现 接下来,我们实现SearchFormTable组件,该组件包含以下功能:
  • 动态渲染搜索表单
  • 根据表单值查询数据
  • 显示数据表格并支持分页
const SearchFormTable: React.FC<SearchFormTableProps> = ({
  searchItems,
  tableColumns,
  fetchDataUrl,
}) => {
  // 组件代码(省略部分代码,详见上文)
};

四、关键功能实现

  1. 动态渲染搜索表单 根据searchItems数组,我们使用map方法动态生成表单项:
const renderFormItem = (item: SearchFormItem) => {
  // 表单项渲染逻辑(省略)
};
  1. 数据查询与表格显示 在handleSearch函数中,我们首先验证表单,然后调用fetchData函数获取数据:
const handleSearch = () => {
  // 查询逻辑(省略)
};

fetchData函数负责与后端服务交互,获取数据并更新表格:

const fetchData = async (params: any) => {
  // 数据获取逻辑(省略)
};

五、代码示例

import React, { useState, useEffect } from 'react';
import { Form, Select, Input, Button, Table, message, DatePicker, Row, Col } from 'antd';
import axios from 'axios';
import moment from 'moment';
import './SearchFormTable.less';

// 定义搜索表单项接口
interface SearchFormItem {
  name: string;
  label: string;
  type: 'input' | 'select' | 'datePicker';
  options?: { label: string; value: string; }[];
}

// 定义表格列接口
interface TableColumn {
  title: string;
  dataIndex: string;
  key: string;
}

// 组件属性接口
interface SearchFormTableProps {
  searchItems: SearchFormItem[];
  tableColumns: TableColumn[];
  fetchDataUrl: string;
}

const SearchFormTable: React.FC<SearchFormTableProps> = ({
  searchItems,
  tableColumns,
  fetchDataUrl,
}) => {
  const [form] = Form.useForm();
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  // 动态渲染表单项
  const renderFormItem = (item: SearchFormItem) => {
    switch (item.type) {
      case 'input':
        return <Input placeholder={`请输入${item.label}`} />;
      case 'select':
        return (
          <Select placeholder={`请选择${item.label}`} allowClear>
            {item.options?.map(option => (
              <Select.Option key={option.value} value={option.value}>
                {option.label}
              </Select.Option>
            ))}
          </Select>
        );
      case 'datePicker':
        return <DatePicker style={{ width: '100%' }} />;
      default:
        return <Input />;
    }
  };

  // 查询数据
  const handleSearch = () => {
    form.validateFields()
      .then(values => {
        setLoading(true);
        fetchData(values);
      })
      .catch(info => {
        console.log('Validate Failed:', info);
      });
  };

  // 重置表单
  const handleReset = () => {
    form.resetFields();
  };

  // 获取数据
  const fetchData = async (params: any) => {
    try {
      const response = await axios.get(fetchDataUrl, { params });
      setData(response.data);
      setLoading(false);
    } catch (error) {
      message.error('数据加载失败');
      setLoading(false);
    }
  };

  useEffect(() => {
    // 组件挂载时获取数据
    fetchData({});
  }, []);

  return (
    <div>
      <Form form={form} layout="vertical">
        <Row gutter={16}>
          {searchItems.map(item => (
            <Col span={8} key={item.name}>
              <Form.Item
                name={item.name}
                label={item.label}
                rules={[{ required: false }]}
              >
                {renderFormItem(item)}
              </Form.Item>
            </Col>
          ))}
          <Col span={8} offset={8} style={{ textAlign: 'right' }}>
            <Button type="primary" htmlType="submit" onClick={handleSearch}>
              查询
            </Button>
            <Button style={{ marginLeft: 8 }} onClick={handleReset}>
              重置
            </Button>
          </Col>
        </Row>
      </Form>
      <Table
        columns={tableColumns}
        dataSource={data}
        loading={loading}
        pagination={{ pageSize: 10 }}
      />
    </div>
  );
};

export default SearchFormTable;

在这个代码示例中,我们定义了SearchFormItemTableColumn接口,用于描述表单项和表格列的结构。SearchFormTable组件接受searchItemstableColumnsfetchDataUrl作为属性,动态生成表单和表格,并处理数据查询逻辑。

六、 模拟数据和运行

首先,我们定义一些模拟的搜索表单项和表格列:

// 模拟的搜索表单项
const searchItems: SearchFormItem[] = [
  {
    name: 'username',
    label: '用户名',
    type: 'input',
  },
  {
    name: 'role',
    label: '角色',
    type: 'select',
    options: [
      { label: '管理员', value: 'admin' },
      { label: '普通用户', value: 'user' },
      { label: '访客', value: 'guest' },
    ],
  },
  {
    name: 'registerDate',
    label: '注册日期',
    type: 'datePicker',
  },
];

// 模拟的表格列
const tableColumns: TableColumn[] = [
  {
    title: '用户名',
    dataIndex: 'username',
    key: 'username',
  },
  {
    title: '角色',
    dataIndex: 'role',
    key: 'role',
  },
  {
    title: '注册日期',
    dataIndex: 'registerDate',
    key: 'registerDate',
  },
];

// 模拟的API端点
const fetchDataUrl = 'https://api.example.com/users';

现在我们可以使用SearchFormTable组件,并将模拟数据传递给它:

import React from 'react';
import ReactDOM from 'react-dom';
import SearchFormTable from './components/SearchFormTable';

const App: React.FC = () => {
  return (
    <div>
      <SearchFormTable
        searchItems={searchItems}
        tableColumns={tableColumns}
        fetchDataUrl={fetchDataUrl}
      />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

假设后端API返回以下格式的数据:

[
  {
    "username": "Alice",
    "role": "admin",
    "registerDate": "2023-01-01"
  },
  {
    "username": "Bob",
    "role": "user",
    "registerDate": "2023-02-15"
  },
  {
    "username": "Charlie",
    "role": "guest",
    "registerDate": "2023-03-10"
  }
]

当用户在SearchFormTable组件中执行搜索时,fetchData函数会被调用,并使用表单的值作为查询参数向fetchDataUrl发送GET请求,后端应处理这些参数并返回相应的数据。

在实际应用中,您需要确保后端API端点fetchDataUrl是正确的,并且能够处理传入的查询参数,返回正确的数据格式。