examples.md•31.5 kB
## List 组件示例
### 简单列表
列表拥有大、中、小三种尺寸。
通过设置 `size` 为 `large` `small` 分别把按钮设为大、小尺寸。若不设置 `size`,则尺寸为中。
可通过设置 `header` 和 `footer`,来自定义列表头部和尾部。
```tsx
import React from 'react';
import { Divider, List, Typography } from 'antd';
const data = [
'Racing car sprays burning fuel into crowd.',
'Japanese princess to wed commoner.',
'Australian walks 100km after outback crash.',
'Man charged over missing wedding girl.',
'Los Angeles battles huge wildfires.',
];
const App: React.FC = () => (
<>
<Divider orientation="left">Default Size</Divider>
<List
header={<div>Header</div>}
footer={<div>Footer</div>}
bordered
dataSource={data}
renderItem={(item) => (
<List.Item>
<Typography.Text mark>[ITEM]</Typography.Text> {item}
</List.Item>
)}
/>
<Divider orientation="left">Small Size</Divider>
<List
size="small"
header={<div>Header</div>}
footer={<div>Footer</div>}
bordered
dataSource={data}
renderItem={(item) => <List.Item>{item}</List.Item>}
/>
<Divider orientation="left">Large Size</Divider>
<List
size="large"
header={<div>Header</div>}
footer={<div>Footer</div>}
bordered
dataSource={data}
renderItem={(item) => <List.Item>{item}</List.Item>}
/>
</>
);
export default App;
```
### 基础列表
基础列表。
```tsx
import React from 'react';
import { Avatar, List } from 'antd';
const data = [
{
title: 'Ant Design Title 1',
},
{
title: 'Ant Design Title 2',
},
{
title: 'Ant Design Title 3',
},
{
title: 'Ant Design Title 4',
},
];
const App: React.FC = () => (
<List
itemLayout="horizontal"
dataSource={data}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`} />}
title={<a href="https://ant.design">{item.title}</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
);
export default App;
```
### 加载更多
可通过 `loadMore` 属性实现加载更多功能。
```tsx
import React, { useEffect, useState } from 'react';
import { Avatar, Button, List, Skeleton } from 'antd';
interface DataType {
gender?: string;
name?: string;
email?: string;
avatar?: string;
loading: boolean;
}
const PAGE_SIZE = 3;
const App: React.FC = () => {
const [initLoading, setInitLoading] = useState(true);
const [loading, setLoading] = useState(false);
const [data, setData] = useState<DataType[]>([]);
const [list, setList] = useState<DataType[]>([]);
const [page, setPage] = useState(1);
const fetchData = (currentPage: number) => {
const fakeDataUrl = `https://660d2bd96ddfa2943b33731c.mockapi.io/api/users?page=${currentPage}&limit=${PAGE_SIZE}`;
return fetch(fakeDataUrl).then((res) => res.json());
};
useEffect(() => {
fetchData(page).then((res) => {
const results = Array.isArray(res) ? res : [];
setInitLoading(false);
setData(results);
setList(results);
});
}, []);
const onLoadMore = () => {
setLoading(true);
setList(data.concat(Array.from({ length: PAGE_SIZE }).map(() => ({ loading: true }))));
const nextPage = page + 1;
setPage(nextPage);
fetchData(nextPage).then((res) => {
const results = Array.isArray(res) ? res : [];
const newData = data.concat(results);
setData(newData);
setList(newData);
setLoading(false);
// Resetting window's offsetTop so as to display react-virtualized demo underfloor.
// In real scene, you can using public method of react-virtualized:
// https://stackoverflow.com/questions/46700726/how-to-use-public-method-updateposition-of-react-virtualized
window.dispatchEvent(new Event('resize'));
});
};
const loadMore =
!initLoading && !loading ? (
<div
style={{
textAlign: 'center',
marginTop: 12,
height: 32,
lineHeight: '32px',
}}
>
<Button onClick={onLoadMore}>loading more</Button>
</div>
) : null;
return (
<List
className="demo-loadmore-list"
loading={initLoading}
itemLayout="horizontal"
loadMore={loadMore}
dataSource={list}
renderItem={(item) => (
<List.Item
actions={[<a key="list-loadmore-edit">edit</a>, <a key="list-loadmore-more">more</a>]}
>
<Skeleton avatar title={false} loading={item.loading} active>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href="https://ant.design">{item.name}</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
<div>content</div>
</Skeleton>
</List.Item>
)}
/>
);
};
export default App;
```
### 竖排列表样式
通过设置 `itemLayout` 属性为 `vertical` 可实现竖排列表样式。
```tsx
import React from 'react';
import { LikeOutlined, MessageOutlined, StarOutlined } from '@ant-design/icons';
import { Avatar, List, Space } from 'antd';
const data = Array.from({ length: 23 }).map((_, i) => ({
href: 'https://ant.design',
title: `ant design part ${i}`,
avatar: `https://api.dicebear.com/7.x/miniavs/svg?seed=${i}`,
description:
'Ant Design, a design language for background applications, is refined by Ant UED Team.',
content:
'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',
}));
const IconText = ({ icon, text }: { icon: React.FC; text: string }) => (
<Space>
{React.createElement(icon)}
{text}
</Space>
);
const App: React.FC = () => (
<List
itemLayout="vertical"
size="large"
pagination={{
onChange: (page) => {
console.log(page);
},
pageSize: 3,
}}
dataSource={data}
footer={
<div>
<b>ant design</b> footer part
</div>
}
renderItem={(item) => (
<List.Item
key={item.title}
actions={[
<IconText icon={StarOutlined} text="156" key="list-vertical-star-o" />,
<IconText icon={LikeOutlined} text="156" key="list-vertical-like-o" />,
<IconText icon={MessageOutlined} text="2" key="list-vertical-message" />,
]}
extra={
<img
draggable={false}
width={272}
alt="logo"
src="https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png"
/>
}
>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href={item.href}>{item.title}</a>}
description={item.description}
/>
{item.content}
</List.Item>
)}
/>
);
export default App;
```
### 分页设置
可通过 `pagination` 属性使用列表分页,并进行设置。
```tsx
import React, { useState } from 'react';
import { Avatar, List, Radio, Space } from 'antd';
type PaginationPosition = 'top' | 'bottom' | 'both';
type PaginationAlign = 'start' | 'center' | 'end';
const data = [
{
title: 'Ant Design Title 1',
},
{
title: 'Ant Design Title 2',
},
{
title: 'Ant Design Title 3',
},
{
title: 'Ant Design Title 4',
},
];
const positionOptions = ['top', 'bottom', 'both'];
const alignOptions = ['start', 'center', 'end'];
const App: React.FC = () => {
const [position, setPosition] = useState<PaginationPosition>('bottom');
const [align, setAlign] = useState<PaginationAlign>('center');
return (
<>
<Space direction="vertical" style={{ marginBottom: '20px' }} size="middle">
<Space>
<span>Pagination Position:</span>
<Radio.Group
optionType="button"
value={position}
onChange={(e) => {
setPosition(e.target.value);
}}
>
{positionOptions.map((item) => (
<Radio.Button key={item} value={item}>
{item}
</Radio.Button>
))}
</Radio.Group>
</Space>
<Space>
<span>Pagination Align:</span>
<Radio.Group
optionType="button"
value={align}
onChange={(e) => {
setAlign(e.target.value);
}}
>
{alignOptions.map((item) => (
<Radio.Button key={item} value={item}>
{item}
</Radio.Button>
))}
</Radio.Group>
</Space>
</Space>
<List
pagination={{ position, align }}
dataSource={data}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`} />}
title={<a href="https://ant.design">{item.title}</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
</>
);
};
export default App;
```
### 栅格列表
可以通过设置 `List` 的 `grid` 属性来实现栅格列表,`column` 可设置期望显示的列数。
```tsx
import React from 'react';
import { Card, List } from 'antd';
const data = [
{
title: 'Title 1',
},
{
title: 'Title 2',
},
{
title: 'Title 3',
},
{
title: 'Title 4',
},
];
const App: React.FC = () => (
<List
grid={{ gutter: 16, column: 4 }}
dataSource={data}
renderItem={(item) => (
<List.Item>
<Card title={item.title}>Card content</Card>
</List.Item>
)}
/>
);
export default App;
```
### 测试栅格列表
List `grid` 在各种情况下的样式表现,如 Fragment 和封装了 List.Item.
```tsx
import React from 'react';
import { Card, List } from 'antd';
const data = [
{
title: 'Title 1',
},
{
title: 'Title 2',
},
{
title: 'Title 3',
},
{
title: 'Title 4',
},
{
title: 'Title 5',
},
{
title: 'Title 6',
},
];
const ListItem = () => (
<List.Item>
<Card title="title">Card content</Card>
</List.Item>
);
const App: React.FC = () => (
<>
<List
grid={{ gutter: 16, column: 4 }}
dataSource={data}
renderItem={(item) => (
<List.Item>
<Card title={item.title}>Card content</Card>
</List.Item>
)}
/>
<List grid={{ gutter: 16, column: 4 }} dataSource={data} renderItem={() => <ListItem />} />
<List
grid={{ gutter: 16, column: 4 }}
dataSource={data}
renderItem={() => (
<>
<ListItem />
<div />
</>
)}
/>
</>
);
export default App;
```
### 响应式的栅格列表
响应式的栅格列表。尺寸与 [Layout Grid](/components/grid-cn/#col) 保持一致。
```tsx
import React from 'react';
import { Card, List } from 'antd';
const data = [
{
title: 'Title 1',
},
{
title: 'Title 2',
},
{
title: 'Title 3',
},
{
title: 'Title 4',
},
{
title: 'Title 5',
},
{
title: 'Title 6',
},
];
const App: React.FC = () => (
<List
grid={{
gutter: 16,
xs: 1,
sm: 2,
md: 4,
lg: 4,
xl: 6,
xxl: 3,
}}
dataSource={data}
renderItem={(item) => (
<List.Item>
<Card title={item.title}>Card content</Card>
</List.Item>
)}
/>
);
export default App;
```
### 滚动加载
结合 [react-infinite-scroll-component](https://github.com/ankeetmaini/react-infinite-scroll-component) 实现滚动自动加载列表。
```tsx
import React, { useEffect, useState } from 'react';
import { Avatar, Divider, List, Skeleton } from 'antd';
import InfiniteScroll from 'react-infinite-scroll-component';
interface DataType {
gender?: string;
name?: string;
email?: string;
avatar?: string;
id?: string;
}
const App: React.FC = () => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<DataType[]>([]);
const [page, setPage] = useState(1);
const loadMoreData = () => {
if (loading) {
return;
}
setLoading(true);
fetch(`https://660d2bd96ddfa2943b33731c.mockapi.io/api/users/?page=${page}&limit=10`)
.then((res) => res.json())
.then((res) => {
const results = Array.isArray(res) ? res : [];
setData([...data, ...results]);
setLoading(false);
setPage(page + 1);
})
.catch(() => {
setLoading(false);
});
};
useEffect(() => {
loadMoreData();
}, []);
return (
<div
id="scrollableDiv"
style={{
height: 400,
overflow: 'auto',
padding: '0 16px',
border: '1px solid rgba(140, 140, 140, 0.35)',
}}
>
<InfiniteScroll
dataLength={data.length}
next={loadMoreData}
hasMore={data.length < 50}
loader={<Skeleton avatar paragraph={{ rows: 1 }} active />}
endMessage={<Divider plain>It is all, nothing more 🤐</Divider>}
scrollableTarget="scrollableDiv"
>
<List
dataSource={data}
renderItem={(item) => (
<List.Item key={item.email}>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href="https://ant.design">{item.name}</a>}
description={item.email}
/>
<div>Content</div>
</List.Item>
)}
/>
</InfiniteScroll>
</div>
);
};
export default App;
```
### 拖拽排序
使用自定义元素,我们可以集成 [dnd-kit](https://github.com/clauderic/dnd-kit) 来实现拖拽排序。
```tsx
import React, { useState } from 'react';
import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
import {
arrayMove,
SortableContext,
useSortable,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { List } from 'antd';
import type { GetProps } from 'antd';
const SortableListItem: React.FC<GetProps<typeof List.Item> & { itemKey: number }> = (props) => {
const { itemKey, style, children, ...rest } = props;
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: itemKey,
});
const listStyle: React.CSSProperties = {
...style,
transform: CSS.Translate.toString(transform),
transition,
cursor: 'move',
...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
};
return (
<List.Item {...rest} ref={setNodeRef} style={listStyle}>
<div {...attributes} {...listeners}>
{children}
</div>
</List.Item>
);
};
const App: React.FC = () => {
const [data, setData] = useState([
{ key: 1, content: 'Racing car sprays burning fuel into crowd.' },
{ key: 2, content: 'Japanese princess to wed commoner.' },
{ key: 3, content: 'Australian walks 100km after outback crash.' },
{ key: 4, content: 'Man charged over missing wedding girl.' },
{ key: 5, content: 'Los Angeles battles huge wildfires.' },
]);
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
// https://docs.dndkit.com/api-documentation/sensors/pointer#activation-constraints
distance: 1,
},
}),
);
const onDragEnd = ({ active, over }: DragEndEvent) => {
if (!active || !over) {
return;
}
if (active.id !== over.id) {
setData((prev) => {
const activeIndex = prev.findIndex((i) => i.key === active.id);
const overIndex = prev.findIndex((i) => i.key === over.id);
return arrayMove(prev, activeIndex, overIndex);
});
}
};
return (
<DndContext
sensors={sensors}
modifiers={[restrictToVerticalAxis]}
onDragEnd={onDragEnd}
id="list-drag-sorting"
>
<SortableContext items={data.map((item) => item.key)} strategy={verticalListSortingStrategy}>
<List
dataSource={data}
renderItem={(item) => (
<SortableListItem key={item.key} itemKey={item.key}>
{item.key} {item.content}
</SortableListItem>
)}
/>
</SortableContext>
</DndContext>
);
};
export default App;
```
### 拖拽排序(拖拽手柄)
使用 [dnd-kit](https://github.com/clauderic/dnd-kit) 来实现一个拖拽操作列。
```tsx
import React, { createContext, useContext, useMemo, useState } from 'react';
import { HolderOutlined } from '@ant-design/icons';
import type { DragEndEvent, DraggableAttributes } from '@dnd-kit/core';
import { DndContext } from '@dnd-kit/core';
import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
import {
arrayMove,
SortableContext,
useSortable,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Button, List } from 'antd';
import type { GetProps } from 'antd';
interface SortableListItemContextProps {
setActivatorNodeRef?: (element: HTMLElement | null) => void;
listeners?: SyntheticListenerMap;
attributes?: DraggableAttributes;
}
const SortableListItemContext = createContext<SortableListItemContextProps>({});
const DragHandle: React.FC = () => {
const { setActivatorNodeRef, listeners, attributes } = useContext(SortableListItemContext);
return (
<Button
type="text"
size="small"
icon={<HolderOutlined />}
style={{ cursor: 'move' }}
ref={setActivatorNodeRef}
{...attributes}
{...listeners}
/>
);
};
const SortableListItem: React.FC<GetProps<typeof List.Item> & { itemKey: number }> = (props) => {
const { itemKey, style, ...rest } = props;
const {
attributes,
listeners,
setNodeRef,
setActivatorNodeRef,
transform,
transition,
isDragging,
} = useSortable({ id: itemKey });
const listStyle: React.CSSProperties = {
...style,
transform: CSS.Translate.toString(transform),
transition,
...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
};
const memoizedValue = useMemo<SortableListItemContextProps>(
() => ({ setActivatorNodeRef, listeners, attributes }),
[setActivatorNodeRef, listeners, attributes],
);
return (
<SortableListItemContext.Provider value={memoizedValue}>
<List.Item {...rest} ref={setNodeRef} style={listStyle} />
</SortableListItemContext.Provider>
);
};
const App: React.FC = () => {
const [data, setData] = useState([
{ key: 1, content: 'Racing car sprays burning fuel into crowd.' },
{ key: 2, content: 'Japanese princess to wed commoner.' },
{ key: 3, content: 'Australian walks 100km after outback crash.' },
{ key: 4, content: 'Man charged over missing wedding girl.' },
{ key: 5, content: 'Los Angeles battles huge wildfires.' },
]);
const onDragEnd = ({ active, over }: DragEndEvent) => {
if (!active || !over) {
return;
}
if (active.id !== over.id) {
setData((prevState) => {
const activeIndex = prevState.findIndex((i) => i.key === active.id);
const overIndex = prevState.findIndex((i) => i.key === over.id);
return arrayMove(prevState, activeIndex, overIndex);
});
}
};
return (
<DndContext
modifiers={[restrictToVerticalAxis]}
onDragEnd={onDragEnd}
id="list-drag-sorting-handler"
>
<SortableContext items={data.map((item) => item.key)} strategy={verticalListSortingStrategy}>
<List
dataSource={data}
renderItem={(item) => (
<SortableListItem key={item.key} itemKey={item.key}>
<DragHandle /> {item.key} {item.content}
</SortableListItem>
)}
/>
</SortableContext>
</DndContext>
);
};
export default App;
```
### 栅格拖拽排序
使用自定义元素,我们可以集成 [dnd-kit](https://github.com/clauderic/dnd-kit) 来实现网格布局的拖拽排序。
```tsx
import React, { useState } from 'react';
import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { arrayMove, SortableContext, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Card, List } from 'antd';
import type { GetProps } from 'antd';
const SortableListItem: React.FC<GetProps<typeof List.Item> & { itemKey: number }> = (props) => {
const { itemKey, style, ...rest } = props;
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: itemKey,
});
const listStyle: React.CSSProperties = {
...style,
transform: CSS.Translate.toString(transform),
transition,
cursor: 'move',
...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
};
return <List.Item {...rest} ref={setNodeRef} style={listStyle} {...attributes} {...listeners} />;
};
const App: React.FC = () => {
const [data, setData] = useState([
{ key: 1, title: 'Title 1' },
{ key: 2, title: 'Title 2' },
{ key: 3, title: 'Title 3' },
{ key: 4, title: 'Title 4' },
{ key: 5, title: 'Title 5' },
{ key: 6, title: 'Title 6' },
]);
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
// https://docs.dndkit.com/api-documentation/sensors/pointer#activation-constraints
distance: 1,
},
}),
);
const onDragEnd = ({ active, over }: DragEndEvent) => {
if (!active || !over) {
return;
}
if (active.id !== over.id) {
setData((prev) => {
const activeIndex = prev.findIndex((i) => i.key === active.id);
const overIndex = prev.findIndex((i) => i.key === over.id);
return arrayMove(prev, activeIndex, overIndex);
});
}
};
return (
<DndContext sensors={sensors} onDragEnd={onDragEnd} id="list-grid-drag-sorting">
<SortableContext items={data.map((item) => item.key)}>
<List
grid={{ gutter: 16, column: 4 }}
dataSource={data}
renderItem={(item) => (
<SortableListItem key={item.key} itemKey={item.key}>
<Card title={item.title}>Card content</Card>
</SortableListItem>
)}
/>
</SortableContext>
</DndContext>
);
};
export default App;
```
### 栅格拖拽排序(拖拽手柄)
使用自定义元素和拖拽手柄,我们可以集成 [dnd-kit](https://github.com/clauderic/dnd-kit) 来实现网格布局的拖拽排序。
```tsx
import React, { createContext, useContext, useMemo, useState } from 'react';
import { HolderOutlined } from '@ant-design/icons';
import type { DragEndEvent, DraggableAttributes } from '@dnd-kit/core';
import { DndContext } from '@dnd-kit/core';
import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';
import { arrayMove, SortableContext, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Button, Card, List } from 'antd';
import type { GetProps } from 'antd';
interface SortableListItemContextProps {
setActivatorNodeRef?: (element: HTMLElement | null) => void;
listeners?: SyntheticListenerMap;
attributes?: DraggableAttributes;
}
const SortableListItemContext = createContext<SortableListItemContextProps>({});
const DragHandle: React.FC = () => {
const { setActivatorNodeRef, listeners, attributes } = useContext(SortableListItemContext);
return (
<Button
type="text"
size="small"
icon={<HolderOutlined />}
style={{ cursor: 'move' }}
ref={setActivatorNodeRef}
{...attributes}
{...listeners}
/>
);
};
const SortableListItem: React.FC<GetProps<typeof List.Item> & { itemKey: number }> = (props) => {
const { itemKey, style, ...rest } = props;
const {
attributes,
listeners,
setNodeRef,
setActivatorNodeRef,
transform,
transition,
isDragging,
} = useSortable({ id: itemKey });
const listStyle: React.CSSProperties = {
...style,
transform: CSS.Translate.toString(transform),
transition,
...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
};
const memoizedValue = useMemo<SortableListItemContextProps>(
() => ({ setActivatorNodeRef, listeners, attributes }),
[setActivatorNodeRef, listeners, attributes],
);
return (
<SortableListItemContext.Provider value={memoizedValue}>
<List.Item {...rest} ref={setNodeRef} style={listStyle} />
</SortableListItemContext.Provider>
);
};
const App: React.FC = () => {
const [data, setData] = useState([
{ key: 1, title: 'Title 1' },
{ key: 2, title: 'Title 2' },
{ key: 3, title: 'Title 3' },
{ key: 4, title: 'Title 4' },
{ key: 5, title: 'Title 5' },
{ key: 6, title: 'Title 6' },
]);
const onDragEnd = ({ active, over }: DragEndEvent) => {
if (!active || !over) {
return;
}
if (active.id !== over.id) {
setData((prevState) => {
const activeIndex = prevState.findIndex((i) => i.key === active.id);
const overIndex = prevState.findIndex((i) => i.key === over.id);
return arrayMove(prevState, activeIndex, overIndex);
});
}
};
return (
<DndContext onDragEnd={onDragEnd} id="list-grid-drag-sorting-handler">
<SortableContext items={data.map((i) => i.key)}>
<List
grid={{ gutter: 16, column: 4 }}
dataSource={data}
renderItem={(item) => (
<SortableListItem key={item.key} itemKey={item.key}>
<Card
title={
<>
<DragHandle />
{item.title}
</>
}
>
Card content
</Card>
</SortableListItem>
)}
/>
</SortableContext>
</DndContext>
);
};
export default App;
```
### 滚动加载无限长列表
结合 [rc-virtual-list](https://github.com/react-component/virtual-list) 实现滚动加载无限长列表,能够提高数据量大时候长列表的性能。
```tsx
import React, { useEffect, useState } from 'react';
import { Avatar, List, message } from 'antd';
import VirtualList from 'rc-virtual-list';
interface UserItem {
email: string;
gender: string;
name: string;
avatar: string;
}
const CONTAINER_HEIGHT = 400;
const PAGE_SIZE = 20;
const App: React.FC = () => {
const [data, setData] = useState<UserItem[]>([]);
const [page, setPage] = useState(1);
const appendData = (showMessage = true) => {
const fakeDataUrl = `https://660d2bd96ddfa2943b33731c.mockapi.io/api/users/?page=${page}&limit=${PAGE_SIZE}`;
fetch(fakeDataUrl)
.then((res) => res.json())
.then((body) => {
const results = Array.isArray(body) ? body : [];
setData(data.concat(results));
setPage(page + 1);
showMessage && message.success(`${results.length} more items loaded!`);
});
};
useEffect(() => {
appendData(false);
}, []);
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {
// Refer to: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#problems_and_solutions
if (
Math.abs(e.currentTarget.scrollHeight - e.currentTarget.scrollTop - CONTAINER_HEIGHT) <= 1
) {
appendData();
}
};
return (
<List>
<VirtualList
data={data}
height={CONTAINER_HEIGHT}
itemHeight={47}
itemKey="email"
onScroll={onScroll}
>
{(item: UserItem) => (
<List.Item key={item.email}>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href="https://ant.design">{item.name}</a>}
description={item.email}
/>
<div>Content</div>
</List.Item>
)}
</VirtualList>
</List>
);
};
export default App;
```
### 自定义组件 token
自定义组件 Token。
```tsx
import React from 'react';
import { Avatar, ConfigProvider, Divider, List, Typography } from 'antd';
const data = [
'Racing car sprays burning fuel into crowd.',
'Japanese princess to wed commoner.',
'Australian walks 100km after outback crash.',
'Man charged over missing wedding girl.',
'Los Angeles battles huge wildfires.',
];
const data1 = [
{
title: 'Ant Design Title 1',
},
{
title: 'Ant Design Title 2',
},
{
title: 'Ant Design Title 3',
},
{
title: 'Ant Design Title 4',
},
];
const App: React.FC = () => (
<ConfigProvider
theme={{
components: {
List: {
headerBg: 'pink',
footerBg: 'pink',
emptyTextPadding: 32,
itemPadding: '26px',
itemPaddingSM: '16px',
itemPaddingLG: '36px',
metaMarginBottom: 20,
avatarMarginRight: 20,
titleMarginBottom: 10,
descriptionFontSize: 20,
},
},
}}
>
<Divider orientation="left">Default Size</Divider>
<List
header={<div>Header</div>}
footer={<div>Footer</div>}
bordered
dataSource={data}
renderItem={(item) => (
<List.Item>
<Typography.Text mark>[ITEM]</Typography.Text> {item}
</List.Item>
)}
/>
<Divider orientation="left">Small Size</Divider>
<List
size="small"
header={<div>Header</div>}
footer={<div>Footer</div>}
bordered
dataSource={data}
renderItem={(item) => <List.Item>{item}</List.Item>}
/>
<Divider orientation="left">Large Size</Divider>
<List
size="large"
header={<div>Header</div>}
footer={<div>Footer</div>}
bordered
dataSource={data}
renderItem={(item) => <List.Item>{item}</List.Item>}
/>
<Divider orientation="left">Meta</Divider>
<List
itemLayout="horizontal"
dataSource={data1}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`} />}
title={<a href="https://ant.design">{item.title}</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
<Divider orientation="left">Vertical</Divider>
<List
itemLayout="vertical"
dataSource={data1}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`} />}
title={<a href="https://ant.design">{item.title}</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
<Divider orientation="left">Empty Text</Divider>
<List />
</ConfigProvider>
);
export default App;
```