• 作者:老汪软件技巧
  • 发表时间:2024-10-08 10:11
  • 浏览量:

如何基于 Ant Design 创建动态表单?关于 Ant Design 上传组件 的入门教程关于 Ant Design 选择组件 的入门教程关于 Ant Design 中单行多列表单布局教程

只要你有需要展示表格数据的需求,那必然离不开操作 组件。Ant Design 中所提供的 组件功能非常丰富,只在一篇文章中是无法覆盖的,本篇只定位它的基础使用。

基础使用

组件,至少要传入 3 个 prop,才能正常展示:一个是 dataSource,一个是 columns,还有一个 rowKey。

import { Table } from 'antd'
function App() {
  return (
    <Table
      dataSource={dataSource}
      columns={columns}
    />
  )
}

假设,我们要展示的数据如下:

const dataSource = [
  {
    id: '1',
    name: '胡彦斌',
    age: 32,
    address: '西湖区湖底公园1号',
  },
  {
    id: '2',
    name: '胡彦祖',
    age: 42,
    address: '西湖区湖底公园2号',
  },
];

那么,表格的 rowKey 就可以设置成具有唯一含义的 id 字段:

<Table
  dataSource={dataSource}
  columns={columns}
  rowKey="id"
/>

当然,rowKey 还可以是一个函数,接受当前行数据为参数,可以让你自定义 rowKey 取值的逻辑。比如:rowKey={(record) => record.login.uuid}

接下来,表格需要展示“姓名”、“年龄”和“住址”这 3 个字段,那么我们就可以这样定义 columns。

const columns = [
  {
    title: '姓名',
    dataIndex: 'name',
  },
  {
    title: '年龄',
    dataIndex: 'age',
  },
  {
    title: '住址',
    dataIndex: 'address',
  },
];

title 表格列名,dataIndex 则表示列名所对应的字段名,有这 2 个就够了。

查看效果:

可以数据被正确渲染出来了。其中,表格各个列默认自动布局,这得益于底层 元素 table-layout: auto; 的设置。

同时,你还能看到右下角还有一个分页标记。没错, 组件还自带了分页展示支持(通过 Pagination 组件)!这一块内容后续我们会细讲,先忽略。

以上,我们就完成了一个表格数据的基础展示案例。

当然,在项目代码中,你可能还会看到设置 columns 使用了 key 字段,这个 key 通常又是跟 dataIndex 是一样的值。

const columns = [
  {
    title: '姓名',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: '年龄',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: '住址',
    dataIndex: 'address',
    key: 'address',
  },
];

说起来,这个 key 其实是在渲染 组件时使用 React key,保证数据刷新时的正确渲染。

不过, 在内部渲染时,帮我们做了一个优化——如果我们已经设置了 dataIndex,那么 key 默认就等于该值,是可以忽略不去设置的。

自定义字段渲染

当然,我们有时面临的渲染场景比较负责,提供的字段仅通过简单的字段渲染是做不到 UI 要求的效果的。

比如,下面的数据:

const data = [
  {
    id: '1',
    name: 'John Brown',
    age: 32,
    address: 'New York No. 1 Lake Park',
    tags: ['nice', 'developer'],
  },
  {
    id: '2',
    name: 'Jim Green',
    age: 42,
    address: 'London No. 1 Lake Park',
    tags: ['loser'],
  },
  {
    id: '3',
    name: 'Joe Black',
    age: 32,
    address: 'Sydney No. 1 Lake Park',
    tags: ['cool', 'teacher'],
  },
];

在渲染时,我们需要对 tags 字段做特殊样式的展示处理,如下所示。

这里,就需要借助标签组件 。

那么 columns 该怎么写呢?前两个比较简单,我们参照上面的案例写出来。

const columns = [
  {
    title: 'Age',
    dataIndex: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
  },
  // ...
]

到了标签这一块,单纯的 dataIndex 是满足不了展示需求的,这个时候就要用到 **render** prop 来自定义渲染样式了。

我们先来看看 render 函数的定义:

render 函数接受 3 个参数:

text:即表示当前渲染的字段值record:则表示当前渲染行的值index:表示当前渲染行的值的索引

那么这就比较好写了:

import { Table, Tag } from 'antd'
const columns = [
  // ...
  {
    title: 'Tags',
    dataIndex: 'tags',
    render: (tags) => (
      <>
        {tags.map((tag) => {
          return (
            <Tag key={tag}>
              {tag.toUpperCase()}
            Tag>
          );
        })}
      
    )
  }
]

当然,render 中的渲染还可以更加丰富:

import { Table, Tag } from 'antd'
const columns = [
  // ...
  {
    title: 'Tags',
    dataIndex: 'tags',
    render: (tags) => (
      <>
        {tags.map((tag) => {
          let color = tag.length > 5 ? 'geekblue' : 'green';
          if (tag === 'loser') {
            color = 'volcano';
          }
          return (
            <Tag color={color} key={tag}>
              {tag.toUpperCase()}
            Tag>
          );
        })}
      
    )
  }
]

最终,展示效果如下:

当然,在自定义渲染时,你可能还会遇到渲染其他一些带有操作行为的字段。

比如下面的 Name 和 Action。

那么就可以这样定义:

const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    render: (name) => <a>{name}a>,
  },
  // ...
  {
    title: 'Action',
    key: 'action',
    render: (_, { name }) => (
      <Space size="middle">
        <a>Invite {name}a>
        <a>Deletea>
      Space>
    ),
  },
]

以上每个 都表示一个操作,可能是个链接跳转,也可能是一次接口请求。限于篇幅,就不具体写实现逻辑了。

注意,最后的 Action 字段,由于并不没有实际对应字段,因此没有设置 dataIndex,但为了更新时的正确渲染,我们设置了 key。

字段排序和过滤

还有 2 个常见的场景,就是进行字段排序和过滤。

排序

先说排序,就要用到 sorter prop。

const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
+   sorter: (a, b) => a.name.localeCompare(b.name),
    render: (name) => {name},
  },
  // ...
}

sorter prop 是一个排序函数,类似 array.sort() 方法的 compareFunction 参数,这里我们是针对姓名做的排序的,使用的是字符串的 localeCompare() 方法。

设置好后,就能看到字段名右侧出现一个排序标志,如此便开启了排序支持。hover 上去时会有提示,点击就可以进行相应排序。

先是升序(asc),后者是降序(desc),排序中的列会有激活样式效果。

针对年龄的排序同理:

{
  title: 'Age',
+ sorter: (a, b) => a.age - b.age,
  dataIndex: 'age',
},

查看效果:

当然,你还可以通过设置 sortDirections prop 设置所支持的排序方式,其默认值是 ['ascend', 'descend'],我们改成 ['ascend'],表示只需要支持升序即可:

{
  title: 'Age',
  sorter: (a, b) => a.age - b.age,
+ sortDirections: ['ascend'],
  dataIndex: 'age',
},

再来看效果:

目前年龄就只支持升序排序了。

表单布局设计_java编写2行2列网格布局_

过滤

再来说说字段过滤。要先实现过滤效果,需要在 column 上的两个 prop 搭配使用:filters 和 onFilter。

const columns = [
  // ...
  {
    title: 'Address',
    dataIndex: 'address',
    filters: [
      {
        text: 'London',
        value: 'London',
      },
      {
        text: 'New York',
        value: 'New York',
      },
    ],
    onFilter: (value, record) => record.address.startsWith(value),
  },
  // ...
]

看看效果:

我们勾选一个选项“London”,点击“OK”,就得到过滤后的结果:

不止如此,对于更加负责的数据结构筛选,filters 也通过 children 来支持:

const columns = [
  // ...
  {
    title: 'Address',
    dataIndex: 'address',
    filters: [
      {
        text: 'London',
        value: 'London',
      },
      {
        text: 'New York',
        value: 'New York',
        children: [
          {
            text: 'Green',
            value: 'Green',
          },
          {
            text: 'Black',
            value: 'Black',
          },
        ],
      },
    ],
    onFilter: (value, record) => {
      console.log('>>>> [onFilter] value: ', value)
      return record.address.startsWith(value)
    },
  },
  // ...
]

效果如下:

这样,就在“New York”之下分离出了“Green”和“Black”2 个子筛选项。筛选后效果:

不过这种情况下,“New York”就无法选中了,这个时候就可以设置 filterMode: 'tree'(默认值 'menu')。

const columns = [
  // ...
  {
    title: 'Address',
    dataIndex: 'address',
+   filterMode: 'tree',
    filters: [/* ... */]
  },
  // ...
]

再来看看效果:

筛选后效果:

可以看到当选择“New York”之后,最终过滤时,过滤条件是包括“New York”本身在内的所有子条件的并集。

渲染分组表头

接下来,再介绍一下关于 UI 层面的一个设置——渲染分组表头,类似下面这样:

不过,我们这里渲染会比较简单,只要改动点就是把 Name 拆分成 FirstName 和 LastName 进行展示:

为了能够实现上述的分组表头展示,我们需要调整下数据源——将 name 字段拆分成 firstName 和 lastName。

const data = [
  {
    id: '1',
    firstName: 'John',
    lastName: 'Brown',
    age: 32,
    address: 'New York No. 1 Lake Park',
    tags: ['nice', 'developer'],
  },
  {
    id: '2',
    firstName: 'Jim',
    lastName: 'Green',
    age: 42,
    address: 'London No. 1 Lake Park',
    tags: ['loser'],
  },
  {
    id: '3',
    firstName: 'Joe',
    lastName: 'Black',
    age: 32,
    address: 'Sydney No. 1 Lake Park',
    tags: ['cool', 'teacher'],
  },
];

为了实现分组表头,就要用到 column 里的 children 字段:

const columns = [
  {
    title: 'Name',
    key: 'name',
    children: [
      {
        title: 'First Name',
        dataIndex: 'firstName',
      },
      {
        title: 'Last Name',
        dataIndex: 'lastName',
      }
    ]
  },
  // ...
]

最终效果如下:

我们再给表格添加边线样式,默认是没有边线效果:

+ bordered
  dataSource={data}
  columns={columns}
  rowKey="id"
/>

再来看看效果:

固定列

对于列数很多的表格,通常需要固定列,横向滚动查看其它数据。在 Ant Design 中,可以通过 fixed prop 来实现(可取值:'left' 和 'right'),不过还要设置 scroll.x/y 配合使用,否则不能生效。

  const columns = [
     // ...
     {
      title: 'Action',
      key: 'action',
+     fixed: 'right',
      render: (_, { name }) => (
        
          Invite {name}
          Delete
        
      ),
    },
  ]
  return (
    
+ scroll={{ x: 1200 }} /> )

效果如下:

其次,你能看到 scroll={{ x: 1200 }} 的设置最终作用到了 元素上。

首先,为了让固定列起作用首先将 table-layout 设置成 fixed,其次设置了 width: 1200px。

当然,我们还可以设置 scroll.y 来限制表格高度:

- scroll={{ x: 1200 }} + scroll={{ x: 1200, y: 120 }} />

效果如下:

scroll.y 反馈到表格内容的包装元素 .ant-table-body 之上,最终反馈为 max-height: 120px。

最后,为了 UI 体验上的提升,默认 table-layout: fixed 之后的表格的列都是等宽的。这通常不是最优的,这个时候可以通过为每列设置 width 来提升体验:

const columns = [
  {
    title: 'Name',
    key: 'name',
    children: [
      {
        title: 'First Name',
        dataIndex: 'firstName',
+       width: 120,
      },
      {
        title: 'Last Name',
        dataIndex: 'lastName',
+       width: 120,
      }
    ]
  },
  {
    title: 'Age',
+   width: 80,
  },
  {
    title: 'Address',
+   width: 220,
    // ...
  },
  {
    title: 'Tags',
+   width: 200,
    // ...
  },
  {
    title: 'Action',
+   width: 220,
    // ...
  },
]

效果如下:

可展示行

当表格内容较多不能一次性完全展示时,可以使用展开列的能力。

以下,我们重新声明 data 和 columns。

const data = [
  {
    id: 1,
    name: 'John Brown',
    age: 32,
    address: 'New York No. 1 Lake Park',
    description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
  },
  {
    id: 2,
    name: 'Jim Green',
    age: 42,
    address: 'London No. 1 Lake Park',
    description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
  },
  {
    id: 3,
    name: 'Not Expandable',
    age: 29,
    address: 'Jiangsu No. 1 Lake Park',
    description: 'This not expandable',
  },
  {
    id: 4,
    name: 'Joe Black',
    age: 32,
    address: 'Sydney No. 1 Lake Park',
    description: 'My name is Joe Black, I am 32 years old, living in Sydney No. 1 Lake Park.',
  },
];

每条数据的 description 属性都是其数据的补充内容,点开时展开。

columns 如下所示:

const columns = [
  { title: 'Name', dataIndex: 'name', key: 'name' },
  { title: 'Age', dataIndex: 'age', key: 'age' },
  { title: 'Address', dataIndex: 'address', key: 'address' },
  {
    title: 'Action',
    key: 'action',
    render: () => <a>Deletea>,
  },
]

中通过 prop 来设置展开行为。其主要有 2 个分关键子属性:expandedRowRender 和 rowExpandable。

+ expandable={{ + expandedRowRender: (record) =>

{record.description}

,
+ rowExpandable: (record) => record.name !== 'Not Expandable', + }} />

效果如下:

每行左侧都会出现一个 + 号,点击即可查看展开内容:

总结

本文,我们总结了 Ant Design 表格组件 的基础使用。主题涉及基本使用、自定义字段渲染、字段排序和筛选、分组表头渲染、固定列和可展示行,基本涵盖了表格的所有基本使用场景。

希望对你的工作能有所帮助,感谢阅读,再见。