Transfer穿梭框

双栏穿梭选择框。

何时使用#

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

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

代码演示

14 itemsSource
Not Found
6 itemsTarget
Not Found

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

expand codeexpand code
import { Transfer } from 'antd';

const mockData = [];
for (let i = 0; i < 20; i++) {
  mockData.push({
    key: i.toString(),
    title: `content${i + 1}`,
    description: `description of content${i + 1}`,
    disabled: i % 3 < 1,
  });
}

const targetKeys = mockData
        .filter(item => +item.key % 3 > 1)
        .map(item => item.key);

class App extends React.Component {
  state = {
    targetKeys,
    selectedKeys: [],
  }

  handleChange = (nextTargetKeys, direction, moveKeys) => {
    this.setState({ targetKeys: nextTargetKeys });

    console.log('targetKeys: ', targetKeys);
    console.log('direction: ', direction);
    console.log('moveKeys: ', moveKeys);
  }

  handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
    this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });

    console.log('sourceSelectedKeys: ', sourceSelectedKeys);
    console.log('targetSelectedKeys: ', targetSelectedKeys);
  }

  handleScroll = (direction, e) => {
    console.log('direction:', direction);
    console.log('target:', e.target);
  }

  render() {
    const state = this.state;
    return (
      <Transfer
        dataSource={mockData}
        titles={['Source', 'Target']}
        targetKeys={state.targetKeys}
        selectedKeys={state.selectedKeys}
        onChange={this.handleChange}
        onSelectChange={this.handleSelectChange}
        onScroll={this.handleScroll}
        render={item => item.title}
      />
    );
  }
}

ReactDOM.render(<App />, mountNode);

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

expand codeexpand code
import { Transfer, Button } from 'antd';

class App extends React.Component {
  state = {
    mockData: [],
    targetKeys: [],
  }
  componentDidMount() {
    this.getMock();
  }
  getMock = () => {
    const targetKeys = [];
    const mockData = [];
    for (let i = 0; i < 20; i++) {
      const data = {
        key: i.toString(),
        title: `content${i + 1}`,
        description: `description of content${i + 1}`,
        chosen: Math.random() * 2 > 1,
      };
      if (data.chosen) {
        targetKeys.push(data.key);
      }
      mockData.push(data);
    }
    this.setState({ mockData, targetKeys });
  }
  handleChange = (targetKeys) => {
    this.setState({ targetKeys });
  }
  renderFooter = () => {
    return (
      <Button
        size="small"
        style={{ float: 'right', margin: 5 }}
        onClick={this.getMock}
      >
        reload
      </Button>
    );
  }
  render() {
    return (
      <Transfer
        dataSource={this.state.mockData}
        showSearch
        listStyle={{
          width: 250,
          height: 300,
        }}
        operations={['to right', 'to left']}
        targetKeys={this.state.targetKeys}
        onChange={this.handleChange}
        render={item => `${item.title}-${item.description}`}
        footer={this.renderFooter}
      />
    );
  }
}

ReactDOM.render(<App />, mountNode);
0 item
    Not Found
    0 item
      Not Found

      自定义渲染每一个 Transfer Item,可用于渲染复杂数据。

      expand codeexpand code
      import { Transfer } from 'antd';
      
      class App extends React.Component {
        state = {
          mockData: [],
          targetKeys: [],
        }
        componentDidMount() {
          this.getMock();
        }
        getMock = () => {
          const targetKeys = [];
          const mockData = [];
          for (let i = 0; i < 20; i++) {
            const data = {
              key: i.toString(),
              title: `content${i + 1}`,
              description: `description of content${i + 1}`,
              chosen: Math.random() * 2 > 1,
            };
            if (data.chosen) {
              targetKeys.push(data.key);
            }
            mockData.push(data);
          }
          this.setState({ mockData, targetKeys });
        }
        handleChange = (targetKeys, direction, moveKeys) => {
          console.log(targetKeys, direction, moveKeys);
          this.setState({ targetKeys });
        }
        renderItem = (item) => {
          const customLabel = (
            <span className="custom-item">
              {item.title} - {item.description}
            </span>
          );
      
          return {
            label: customLabel,  // for displayed item
            value: item.title,   // for title and filter matching
          };
        }
        render() {
          return (
            <Transfer
              dataSource={this.state.mockData}
              listStyle={{
                width: 300,
                height: 300,
              }}
              targetKeys={this.state.targetKeys}
              onChange={this.handleChange}
              render={this.renderItem}
            />
          );
        }
      }
      
      ReactDOM.render(<App />, mountNode);

      API#

      参数说明类型默认值
      dataSource数据源,其中的数据将会被渲染到左边一栏中,targetKeys 中指定的除外。TransferItem[][]
      render每行数据渲染函数,该函数的入参为 dataSource 中的项,返回值为 ReactElementFunction(record)
      targetKeys显示在右侧框数据的key集合string[][]
      selectedKeys设置哪些项应该被选中string[][]
      onChange选项在两栏之间转移时的回调函数(targetKeys, direction, moveKeys): void
      onSelectChange选中项发生改变时的回调函数(sourceSelectedKeys, targetSelectedKeys): void
      onScroll选项列表滚动时的回调函数(direction, event): void
      listStyle两个穿梭框的自定义样式object
      className自定义类string
      titles标题集合,顺序从左至右string[]'', ''
      operations操作文案集合,顺序从下至上string[]'>', '<'
      showSearch是否显示搜索框booleanfalse
      filterOption接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false(inputValue, option): boolean
      searchPlaceholder搜索框的默认值string'请输入搜索内容'
      notFoundContent当列表为空时显示的内容string|ReactNode'列表为空'
      footer底部渲染函数(props): ReactNode
      lazyTransfer 使用了 react-lazy-load 优化性能,这里可以设置相关参数。设为 false 可以关闭懒加载。object|boolean{ height: 32, offset: 32 }
      onSearchChange搜索框内容时改变时的回调函数(direction: 'left'|'right', event: Event): void-

      注意#

      按照 React 的规范,所有的组件数组必须绑定 key。在 Transfer 中,dataSource里的数据值需要指定 key 值。对于 dataSource 默认将每列数据的 key 属性作为唯一的标识。

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

      // 比如你的数据主键是 uid
      return <Transfer rowKey={record => record.uid} />;