Ant Design穿梭框:Transfer组件数据交互实现
组件概述
Ant Design的Transfer(穿梭框)组件是一个双栏穿梭选择框,用于在两个列表之间移动数据项。它主要应用于以下场景:
- 需要在多个可选项中进行多选时
- 比起Select和TreeSelect,需要展示更多信息时
该组件位于项目的components/transfer/目录下,核心实现文件为components/transfer/index.tsx。
基本用法
Transfer组件最基础的用法是展示两个列表,通过方向按钮在列表间移动选项。基本实现代码如下:
import { Transfer } from 'antd';
const App = () => {
const [targetKeys, setTargetKeys] = useState([]);
const [selectedKeys, setSelectedKeys] = useState([]);
const dataSource = [...Array(20)].map((_, i) => ({
key: i.toString(),
title: `选项 ${i + 1}`,
description: `选项 ${i + 1} 的描述信息`,
}));
return (
<Transfer
dataSource={dataSource}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
onChange={setTargetKeys}
onSelectChange={setSelectedKeys}
render={(item) => `${item.title}-${item.description}`}
/>
);
};
这个基础示例展示了Transfer组件的核心功能:
- 左侧列表显示可用选项
- 右侧列表显示已选选项
- 可通过中间的方向按钮移动选项
核心API参数
Transfer组件提供了丰富的API来自定义其行为,主要参数包括:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| dataSource | 数据源,渲染到左边一栏中 | RecordType[] | [] |
| targetKeys | 显示在右侧框数据的key集合 | TransferKey[] | [] |
| selectedKeys | 设置哪些项应该被选中 | TransferKey[] | [] |
| render | 每行数据渲染函数 | (record) => ReactNode | - |
| onChange | 选项在两栏之间转移时的回调 | (targetKeys, direction, moveKeys) => void | - |
| onSelectChange | 选中项发生改变时的回调 | (sourceSelectedKeys, targetSelectedKeys) => void | - |
完整的API文档可参考components/transfer/index.zh-CN.md。
数据交互核心实现
数据处理流程
Transfer组件的数据处理核心逻辑位于components/transfer/hooks/useData.ts文件中。该hooks负责:
- 处理数据源,为每个项添加唯一key
- 根据targetKeys分离左右列表数据
- 提供过滤和排序功能
核心代码逻辑如下:
// 简化版数据处理逻辑
const useData = (dataSource, rowKey, targetKeys) => {
// 处理数据源,确保每个项都有key
const mergedDataSource = (dataSource || []).map((record) => {
const key = rowKey ? rowKey(record) : record.key;
return { ...record, key };
});
// 分离左右列表数据
const leftDataSource = mergedDataSource.filter(
(item) => !targetKeys.includes(item.key)
);
const rightDataSource = mergedDataSource.filter(
(item) => targetKeys.includes(item.key)
);
return [mergedDataSource, leftDataSource, rightDataSource];
};
选择状态管理
选择状态管理由components/transfer/hooks/useSelection.ts实现,负责维护选中项的状态:
// 简化版选择状态管理
const useSelection = (leftDataSource, rightDataSource, selectedKeys) => {
const [sourceSelectedKeys, setSourceSelectedKeys] = useState([]);
const [targetSelectedKeys, setTargetSelectedKeys] = useState([]);
// 处理选中项变化逻辑
// ...
return [
sourceSelectedKeys,
targetSelectedKeys,
setSourceSelectedKeys,
setTargetSelectedKeys
];
};
移动选项实现
移动选项的核心逻辑在Transfer组件的moveTo方法中实现:
const moveTo = (direction) => {
// 确定要移动的键
const moveKeys = direction === 'right' ? sourceSelectedKeys : targetSelectedKeys;
// 过滤禁用选项
const dataSourceDisabledKeysMap = groupDisabledKeysMap(mergedDataSource);
const newMoveKeys = moveKeys.filter((key) => !dataSourceDisabledKeysMap.has(key));
// 更新目标键集合
const newTargetKeys = direction === 'right'
? newMoveKeys.concat(targetKeys)
: targetKeys.filter((targetKey) => !newMoveKeys.includes(targetKey));
// 清空选中状态
const oppositeDirection = direction === 'right' ? 'left' : 'right';
setStateKeys(oppositeDirection, []);
// 触发回调
onChange(newTargetKeys, direction, newMoveKeys);
};
高级功能
带搜索功能
Transfer组件支持搜索过滤功能,只需设置showSearch为true:
<Transfer
dataSource={dataSource}
targetKeys={targetKeys}
showSearch
filterOption={(inputValue, item) =>
item.title.toLowerCase().includes(inputValue.toLowerCase())
}
/>
搜索功能的实现位于components/transfer/search.tsx文件中。
自定义渲染
Transfer组件支持高度自定义的渲染方式,包括自定义列表内容、标题和底部内容:
<Transfer
dataSource={dataSource}
targetKeys={targetKeys}
render={(item) => (
<div>
<div>{item.title}</div>
<div style={{ fontSize: 12, color: '#666' }}>{item.description}</div>
</div>
)}
footer={(props) => (
<div>
<Button size="small" onClick={props.clear} disabled={props.disabled}>
清空
</Button>
</div>
)}
/>
表格穿梭框
Transfer组件支持与Table组件结合使用,实现更复杂的数据展示和选择功能:
<Transfer
dataSource={dataSource}
targetKeys={targetKeys}
rowKey="key"
>
{({ direction, filteredItems, onItemSelect, selectedKeys }) => (
<Table
dataSource={filteredItems}
rowKey="key"
pagination={false}
rowSelection={{
type: 'checkbox',
selectedRowKeys: selectedKeys,
onChange: (keys) => onItemSelect(keys, true),
}}
>
<Table.Column title="姓名" dataIndex="name" key="name" />
<Table.Column title="年龄" dataIndex="age" key="age" />
</Table>
)}
</Transfer>
这个高级示例的完整实现可参考components/transfer/demo/table-transfer.tsx。
常见问题与注意事项
数据唯一性
按照React的规范,所有的组件数组必须绑定key。在Transfer中,dataSource里的数据值需要指定key值。如果数据没有这个属性,务必使用rowKey来指定数据列的主键:
// 当数据主键是uid时
<Transfer rowKey={(record) => record.uid} />
异步数据加载
处理异步数据加载时,可以通过控制dataSource来实现:
const [dataSource, setDataSource] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetchData().then(data => {
setDataSource(data);
setLoading(false);
});
}, []);
return (
<Transfer
dataSource={dataSource}
loading={loading}
// 其他属性
/>
);
性能优化
当处理大量数据时,建议使用分页功能来优化性能:
<Transfer
dataSource={dataSource}
pagination={{ pageSize: 10 }}
/>
总结
Ant Design的Transfer组件提供了强大而灵活的数据穿梭功能,通过本文的介绍,我们了解了:
- Transfer组件的基本用法和核心API
- 数据交互的核心实现原理
- 高级功能如自定义渲染和表格集成
- 常见问题和性能优化建议
更多详细的使用示例可以参考components/transfer/demo/目录下的文件,包括基本用法、搜索功能、高级自定义等多种场景的实现。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



