2025年07月23日秋瑶传媒一面
目录
- react 如何封装一个 table 组件
- react 父子组件传值
- 讲一下 umi
- umi 的状态管理的使用
- 介绍下你的项目难点
- 讲一下你们小程序是怎么做的
- tooltip 组件怎么自定义判断 2 行 3 行的时候展示
- umi 怎么动态加载 css js
- umi 怎么使用状态管理
1. react 如何封装一个 table 组件
我将为你提供一个封装 Ant Design Table 组件的方案,使其具有类似 Ant Design Pro 的高级功能。这种封装可以提高代码复用性,简化表格使用,并统一项目中的表格风格。
封装思路
我们将创建一个 ProTable
组件,支持以下核心功能:
- 自动处理分页、排序、筛选
- 支持搜索表单
- 集成请求数据的 Hooks
- 自动生成表格列配置
- 支持操作栏自定义
- 统一的样式风格
组件实现
下面是一个完整的 ProTable
组件实现:
import React, { useState, useMemo, useCallback, useEffect } from 'react';
import { Table, Form, Button, Space, Input, Select, Popconfirm } from 'antd';
import { SearchOutlined, ReloadOutlined } from '@ant-design/icons';
import { debounce } from 'lodash';const { Item } = Form;
const { Option } = Select;/*** ProTable 组件 - 封装 Ant Design Table 提供高级功能* @param {Object} props - 组件属性* @param {Array} props.columns - 表格列配置* @param {Function} props.request - 获取数据的请求函数* @param {Object} props.formItems - 搜索表单配置* @param {Object} props.initialValues - 初始表单值* @param {Boolean} props.loading - 加载状态* @param {Function} props.onRow - 行点击事件* @param {Function} props.rowKey - 行键* @param {Object} props.tableProps - 传递给 Table 的其他属性*/
const ProTable = ({columns = [],request,formItems = [],initialValues = {},loading = false,onRow,rowKey = 'id',tableProps = {},
}) => {const [form] = Form.useForm();const [dataSource, setDataSource] = useState([]);const [pagination, setPagination] = useState({current: 1,pageSize: 10,total: 0,});const [sorter, setSorter] = useState({});const [filters, setFilters] = useState({});// 处理搜索表单值变化const handleFormValuesChange = useCallback((changedValues, allValues) => {// 重置分页setPagination(prev => ({...prev,current: 1,}));// 更新筛选条件setFilters(allValues);}, []);// 处理分页变化const handleTableChange = useCallback((pagination, filters, sorter) => {setPagination(pagination);setFilters(filters);setSorter(sorter);}, []);// 构建搜索表单const renderFormItems = useMemo(() => {return formItems.map(item => {const { key, title, type = 'input', options = [], ...rest } = item;switch (type) {case 'select':return (<Item key={key} label={title} name={key} {...rest}><Select placeholder={`请选择${title}`}>{options.map(option => (<Option key={option.value} value={option.value}>{option.label}</Option>))}</Select></Item>);case 'input':default:return (<Item key={key} label={title} name={key} {...rest}><Input placeholder={`请输入${title}`} /></Item>);}});}, [formItems]);// 处理搜索const handleSearch = useCallback(() => {// 重置分页setPagination(prev => ({...prev,current: 1,}));// 触发数据加载fetchData();}, [fetchData]);// 处理重置const handleReset = useCallback(() => {form.resetFields();// 重置分页和筛选setPagination({current: 1,pageSize: 10,total: 0,});setFilters({});setSorter({});// 触发数据加载fetchData();}, [form, fetchData]);// 构建表格列配置const buildColumns = useMemo(() => {return columns.map(column => {// 如果有操作列,添加固定位置if (column.key === 'actions') {return {...column,fixed: 'right',width: 180,};}return column;});}, [columns]);// 合并表格属性const mergedTableProps = useMemo(() => {return {rowKey,dataSource,pagination,loading,onChange: handleTableChange,onRow,columns: buildColumns,...tableProps,};}, [dataSource, pagination, loading, handleTableChange, onRow, buildColumns, tableProps, rowKey]);// 数据加载const fetchData = useCallback(async () => {if (!request) return;try {const { current, pageSize } = pagination;const { field, order } = sorter;const response = await request({page: current,pageSize,sortField: field,sortOrder: order === 'ascend' ? 'asc' : 'desc',...filters,});setDataSource(response.data || []);setPagination(prev => ({...prev,total: response.total || 0,}));} catch (error) {console.error('Failed to fetch data:', error);}}, [request, pagination, sorter, filters]);// 初始化数据useEffect(() => {form.setFieldsValue(initialValues);fetchData();}, [form, initialValues, fetchData]);// 防抖搜索const debouncedSearch = useCallback(debounce(handleSearch, 500),[handleSearch]);return (<div className="pro-table-container">{formItems.length > 0 && (<Formform={form}layout="inline"onValuesChange={handleFormValuesChange}initialValues={initialValues}><div className="pro-table-search-bar"><Space>{renderFormItems}<Item><Button type="primary" onClick={handleSearch} icon={<SearchOutlined />}>搜索</Button></Item><Item><Button onClick={handleReset}>重置</Button></Item></Space></div></Form>)}<Table {...mergedTableProps} /></div>);
};export default ProTable;
使用示例
下面是如何使用这个封装组件的示例:
import React from 'react';
import ProTable from './ProTable';// 模拟API请求
const fetchTableData = async ({ page, pageSize, sortField, sortOrder, ...filters }) => {// 这里应该是实际的API调用console.log('Fetching data with params:', { page, pageSize, sortField, sortOrder, filters });// 模拟返回数据return new Promise(resolve => {setTimeout(() => {resolve({data: [{ id: 1, name: '张三', age: 28, address: '北京市朝阳区', status: 'active' },{ id: 2, name: '李四', age: 32, address: '上海市浦东新区', status: 'inactive' },{ id: 3, name: '王五', age: 45, address: '广州市天河区', status: 'active' },],total: 100,});}, 800);});
};// 表格列配置
const columns = [{title: 'ID',dataIndex: 'id',key: 'id',sorter: true,},{title: '姓名',dataIndex: 'name',key: 'name',sorter: true,},{title: '年龄',dataIndex: 'age',key: 'age',sorter: true,},{title: '地址',dataIndex: 'address',key: 'address',},{title: '状态',dataIndex: 'status',key: 'status',filters: [{ text: '活跃', value: 'active' },{ text: '非活跃', value: 'inactive' },],onFilter: (value, record) => record.status === value,},{title: '操作',key: 'actions',render: (_, record) => (<Space size="small"><a href="#">查看</a><a href="#">编辑</a><Popconfirm title="确定要删除吗?" onConfirm={() => console.log('Delete:', record.id)}><a href="#">删除</a></Popconfirm></Space>),},
];// 搜索表单配置
const formItems = [{key: 'name',title: '姓名',},{key: 'status',title: '状态',type: 'select',options: [{ label: '全部', value: '' },{ label: '活跃', value: 'active' },{ label: '非活跃', value: 'inactive' },],},
];// 页面组件
const MyTablePage = () => {return (<div className="page-container"><h1>用户列表</h1><ProTablecolumns={columns}request={fetchTableData}formItems={formItems}initialValues={{ status: 'active' }}/></div>);
};export default MyTablePage;
样式优化(可选)
添加一些全局样式可以使表格看起来更像 Ant Design Pro:
/* pro-table.css */
.pro-table-container {background-color: #fff;border-radius: 8px;padding: 20px;margin-bottom: 20px;box-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09);
}.pro-table-search-bar {margin-bottom: 16px;padding-bottom: 16px;border-bottom: 1px solid #f0f0f0;
}/* 表格样式优化 */
.ant-table-thead > tr > th {background-color: #fafafa;font-weight: 600;
}.ant-table-tbody > tr:hover > td {background-color: #f5f7fa !important;
}.ant-pagination {margin-top: 16px !important;
}
封装优势
- 统一风格:所有表格使用相同的样式和交互逻辑
- 简化使用:只需提供列配置和数据请求函数
- 自动处理分页/排序/筛选:减少重复代码
- 可扩展:可以轻松添加新功能(如导出、批量操作)
- 易于维护:一处修改,所有表格生效
你可以根据项目需求进一步扩展这个组件,比如添加批量操作、导出功能、行选择等。