Transfer穿梭框

    • 需要在多个可选项中进行多选时。

    • 比起 Select 和 TreeSelect,穿梭框占据更大的空间,可以展示可选项的更多信息。

    穿梭选择框用直观的方式在两栏中移动元素,完成选择行为。

    选择一个或以上的选项后,点击对应的方向键,可以把选中的选项移动到另一栏。其中,左边一栏为 ,右边一栏为 target,API 的设计也反映了这两个概念。

    基本用法

    最基本的用法,展示了 dataSourcetargetKeys、每行的渲染函数 render 以及回调函数 onChange onSelectChange onScroll 的用法。

    带搜索框的穿梭框,可以自定义搜索函数。

    1. import { Transfer } from 'antd';
    2. class App extends React.Component {
    3. state = {
    4. mockData: [],
    5. targetKeys: [],
    6. };
    7. componentDidMount() {
    8. this.getMock();
    9. }
    10. getMock = () => {
    11. const targetKeys = [];
    12. const mockData = [];
    13. for (let i = 0; i < 20; i++) {
    14. const data = {
    15. key: i.toString(),
    16. title: `content${i + 1}`,
    17. description: `description of content${i + 1}`,
    18. chosen: Math.random() * 2 > 1,
    19. };
    20. if (data.chosen) {
    21. targetKeys.push(data.key);
    22. }
    23. mockData.push(data);
    24. }
    25. this.setState({ mockData, targetKeys });
    26. };
    27. filterOption = (inputValue, option) => option.description.indexOf(inputValue) > -1;
    28. handleChange = targetKeys => {
    29. this.setState({ targetKeys });
    30. };
    31. handleSearch = (dir, value) => {
    32. console.log('search:', dir, value);
    33. };
    34. render() {
    35. return (
    36. <Transfer
    37. dataSource={this.state.mockData}
    38. showSearch
    39. filterOption={this.filterOption}
    40. targetKeys={this.state.targetKeys}
    41. onChange={this.handleChange}
    42. onSearch={this.handleSearch}
    43. render={item => item.title}
    44. />
    45. );
    46. }
    47. }
    48. ReactDOM.render(<App />, mountNode);

    Transfer 穿梭框 - 图3

    高级用法

    穿梭框高级用法,可配置操作文案,可定制宽高,可对底部进行自定义渲染。

    1. import { Transfer } from 'antd';
    2. class App extends React.Component {
    3. state = {
    4. mockData: [],
    5. targetKeys: [],
    6. };
    7. componentDidMount() {
    8. this.getMock();
    9. }
    10. getMock = () => {
    11. const targetKeys = [];
    12. for (let i = 0; i < 20; i++) {
    13. const data = {
    14. key: i.toString(),
    15. title: `content${i + 1}`,
    16. description: `description of content${i + 1}`,
    17. chosen: Math.random() * 2 > 1,
    18. if (data.chosen) {
    19. targetKeys.push(data.key);
    20. }
    21. mockData.push(data);
    22. }
    23. this.setState({ mockData, targetKeys });
    24. };
    25. handleChange = (targetKeys, direction, moveKeys) => {
    26. console.log(targetKeys, direction, moveKeys);
    27. this.setState({ targetKeys });
    28. };
    29. renderItem = item => {
    30. const customLabel = (
    31. <span className="custom-item">
    32. {item.title} - {item.description}
    33. </span>
    34. );
    35. return {
    36. label: customLabel, // for displayed item
    37. value: item.title, // for title and filter matching
    38. };
    39. };
    40. render() {
    41. return (
    42. <Transfer
    43. dataSource={this.state.mockData}
    44. listStyle={{
    45. width: 300,
    46. height: 300,
    47. }}
    48. targetKeys={this.state.targetKeys}
    49. onChange={this.handleChange}
    50. render={this.renderItem}
    51. />
    52. );
    53. }
    54. }
    55. ReactDOM.render(<App />, mountNode);

    Transfer 穿梭框 - 图5

    表格穿梭框

    使用 Table 组件作为自定义渲染列表。

    使用 Tree 组件作为自定义渲染列表。

    1. import { Transfer, Tree } from 'antd';
    2. const { TreeNode } = Tree;
    3. // Customize Table Transfer
    4. const isChecked = (selectedKeys, eventKey) => {
    5. return selectedKeys.indexOf(eventKey) !== -1;
    6. };
    7. const generateTree = (treeNodes = [], checkedKeys = []) => {
    8. return treeNodes.map(({ children, ...props }) => (
    9. <TreeNode {...props} disabled={checkedKeys.includes(props.key)}>
    10. {generateTree(children, checkedKeys)}
    11. </TreeNode>
    12. ));
    13. };
    14. const TreeTransfer = ({ dataSource, targetKeys, ...restProps }) => {
    15. const transferDataSource = [];
    16. function flatten(list = []) {
    17. list.forEach(item => {
    18. transferDataSource.push(item);
    19. flatten(item.children);
    20. });
    21. }
    22. flatten(dataSource);
    23. return (
    24. <Transfer
    25. targetKeys={targetKeys}
    26. dataSource={transferDataSource}
    27. className="tree-transfer"
    28. render={item => item.title}
    29. showSelectAll={false}
    30. >
    31. {({ direction, onItemSelect, selectedKeys }) => {
    32. if (direction === 'left') {
    33. const checkedKeys = [...selectedKeys, ...targetKeys];
    34. return (
    35. <Tree
    36. checkable
    37. checkStrictly
    38. defaultExpandAll
    39. checkedKeys={checkedKeys}
    40. onCheck={(
    41. _,
    42. {
    43. node: {
    44. props: { eventKey },
    45. },
    46. },
    47. ) => {
    48. onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
    49. }}
    50. onSelect={(
    51. _,
    52. {
    53. node: {
    54. props: { eventKey },
    55. },
    56. },
    57. ) => {
    58. onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
    59. }}
    60. >
    61. {generateTree(dataSource, targetKeys)}
    62. </Tree>
    63. );
    64. }
    65. }}
    66. </Transfer>
    67. );
    68. };
    69. const treeData = [
    70. { key: '0-0', title: '0-0' },
    71. {
    72. key: '0-1',
    73. title: '0-1',
    74. children: [{ key: '0-1-0', title: '0-1-0' }, { key: '0-1-1', title: '0-1-1' }],
    75. },
    76. { key: '0-2', title: '0-3' },
    77. ];
    78. class App extends React.Component {
    79. state = {
    80. targetKeys: [],
    81. };
    82. onChange = targetKeys => {
    83. console.log('Target Keys:', targetKeys);
    84. this.setState({ targetKeys });
    85. };
    86. render() {
    87. const { targetKeys } = this.state;
    88. return (
    89. <div>
    90. <TreeTransfer dataSource={treeData} targetKeys={targetKeys} onChange={this.onChange} />
    91. </div>
    92. );
    93. }
    94. }
    95. ReactDOM.render(<App />, mountNode);

    Render Props

    3.18.0 新增。Transfer 支持接收 children 自定义渲染列表,并返回以下参数:

    参数说明类型版本
    direction渲染列表的方向'left' | 'right'3.18.0
    disabled是否禁用列表boolean3.18.0
    filteredItems过滤后的数据TransferItem[]3.18.0
    onItemSelect勾选条目(key: string, selected: boolean)3.18.0
    onItemSelectAll勾选一组条目(keys: string[], selected: boolean)3.18.0
    selectedKeys选中的条目string[]3.18.0

    参考示例

    如果你的数据没有这个属性,务必使用 rowKey 来指定数据列的主键。

    1. // 比如你的数据主键是 uid